diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index c314b149cb..2b8d34012e 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -15,7 +15,7 @@ jobs: strategy: matrix: os: [ubuntu-latest] - python-version: [3.7] + python-version: [3.8] timeout-minutes: 30 @@ -32,7 +32,7 @@ jobs: sudo apt-get update --fix-missing sudo apt-get autoremove sudo apt-get autoclean - pip install tomte[tox]==0.2.4 + pip install tomte[tox]==0.2.15 sudo npm install -g markdown-spellcheck - name: Generate Documentation run: tox -e docs diff --git a/.github/workflows/main_workflow.yml b/.github/workflows/main_workflow.yml index 987feb0304..ddcefc20aa 100644 --- a/.github/workflows/main_workflow.yml +++ b/.github/workflows/main_workflow.yml @@ -30,7 +30,7 @@ jobs: - if: matrix.os != 'windows-latest' name: Pipenv install requirements and check it can be locked run: | - pip install pipenv + pip install pipenv==2023.7.23 pipenv --clear time pipenv install --verbose --dev --skip-lock time pipenv run pip install -e .[all] @@ -39,13 +39,13 @@ jobs: name: Pipenv install requirements and check it can be locked run: | choco install ptime - pip install pipenv + pip install pipenv==2023.7.23 pipenv --clear ptime pipenv install --verbose --dev --skip-lock ptime pipenv run pip install -e .[all] ptime pipenv lock - copyright_doc_and_pipfile_check: + copyright_doc_and_dependencies_check: continue-on-error: False runs-on: ${{ matrix.os }} @@ -68,18 +68,20 @@ jobs: sudo apt-get update --fix-missing sudo apt-get autoremove sudo apt-get autoclean - pip install tomte[tox]==0.2.4 + pip install tomte[tox,cli]==0.2.15 pip install --user --upgrade setuptools - name: Check copyright headers - run: tox -e check-copyright + run: tomte format-copyright --author valory --author fetchai - name: License compatibility check run: tox -e liccheck - name: Check docs run: tox -e check-api-docs - - name: Check doc links and IPFS hashes - run: tox -e check-doc-links-hashes - - name: Check pipfiles - run: tox -e check-pipfiles + - name: Check doc links + run: tomte check-doc-links --http-skips http://host.docker.internal:8545 --http-skips http://www.fipa.org/repository/ips.php3 --url-skips "https://gateway.autonolas.tech/ipfs/," --url-skips "https://github.com/valory-xyz/open-autonomy/trunk/infrastructure" --url-skips "http://host.docker.internal:8545" --url-skips "https://github.com/valory-xyz/open-operator" + - name: Check doc IPFS hashes + run: tox -e check-doc-hashes + - name: Check dependencies + run: tox -e check-dependencies linter_checks: continue-on-error: False @@ -105,11 +107,11 @@ jobs: sudo apt-get update --fix-missing sudo apt-get autoremove sudo apt-get autoclean - pip install tomte[tox]==0.2.4 + pip install tomte[tox]==0.2.15 pip install --user --upgrade setuptools # install Protobuf compiler - wget https://github.com/protocolbuffers/protobuf/releases/download/v3.19.4/protoc-3.19.4-linux-x86_64.zip - unzip protoc-3.19.4-linux-x86_64.zip -d protoc + wget https://github.com/protocolbuffers/protobuf/releases/download/v24.3/protoc-24.3-linux-x86_64.zip + unzip protoc-24.3-linux-x86_64.zip -d protoc sudo mv protoc/bin/protoc /usr/local/bin/protoc # install IPFS sudo apt-get install -y wget @@ -169,14 +171,14 @@ jobs: continue-on-error: True needs: - lock_check - - copyright_doc_and_pipfile_check + - copyright_doc_and_dependencies_check - linter_checks runs-on: ${{ matrix.os }} strategy: matrix: os: [ ubuntu-latest, macos-latest, windows-latest ] - python-version: [ "3.7", "3.8", "3.9", "3.10.9" ] + python-version: [ "3.8", "3.9", "3.10.9", "3.11" ] timeout-minutes: 90 @@ -197,12 +199,12 @@ jobs: sudo apt-get update --fix-missing sudo apt-get autoremove sudo apt-get autoclean - pip install tomte[tox]==0.2.4 + pip install tomte[tox]==0.2.15 pip install --user --upgrade setuptools # install Protobuf compiler - wget https://github.com/protocolbuffers/protobuf/releases/download/v3.19.4/protoc-3.19.4-linux-x86_64.zip - unzip protoc-3.19.4-linux-x86_64.zip -d protoc + wget https://github.com/protocolbuffers/protobuf/releases/download/v24.3/protoc-24.3-linux-x86_64.zip + unzip protoc-24.3-linux-x86_64.zip -d protoc sudo mv protoc/bin/protoc /usr/local/bin/protoc # install IPFS @@ -251,12 +253,12 @@ jobs: - if: matrix.os == 'macos-latest' name: Install dependencies (macos-latest) run: | - pip install tomte[tox]==0.2.4 + pip install tomte[tox]==0.2.15 brew install gcc # brew install protobuf # brew install https://raw.githubusercontent.com/Homebrew/homebrew-core/72457f0166d5619a83f508f2345b22d0617b5021/Formula/protobuf.rb - wget https://github.com/protocolbuffers/protobuf/releases/download/v3.19.4/protoc-3.19.4-osx-x86_64.zip - unzip protoc-3.19.4-osx-x86_64.zip -d protoc + wget https://github.com/protocolbuffers/protobuf/releases/download/v24.3/protoc-24.3-osx-x86_64.zip + unzip protoc-24.3-osx-x86_64.zip -d protoc sudo mv protoc/bin/protoc /usr/local/bin/protoc brew tap yoheimuta/protolint brew install protolint @@ -299,14 +301,14 @@ jobs: python -m pip install -U pip echo "::add-path::C:\Program Files (x86)\Windows Kits\10\bin\10.0.18362.0\x64" choco install wget -y - choco install protoc --version 3.19.4 + choco install protoc --version 24.3 choco install mingw -y choco install make -y # to check make was installed make --version - pip install tomte[tox]==0.2.4 - # wget https://github.com/protocolbuffers/protobuf/releases/download/v3.19.4/protoc-3.19.4-win64.zip - # unzip protoc-3.19.4-win64.zip -d protoc + pip install tomte[tox]==0.2.15 + # wget https://github.com/protocolbuffers/protobuf/releases/download/v24.3/protoc-24.3-win64.zip + # unzip protoc-24.3-win64.zip -d protoc # sudo mv protoc/bin/protoc /usr/local/bin/protoc # TODO: install protolint @@ -356,7 +358,7 @@ jobs: continue-on-error: True needs: - lock_check - - copyright_doc_and_pipfile_check + - copyright_doc_and_dependencies_check - linter_checks runs-on: ${{ matrix.os }} @@ -379,12 +381,12 @@ jobs: sudo apt-get update --fix-missing sudo apt-get autoremove sudo apt-get autoclean - pip install tomte[tox]==0.2.4 + pip install tomte[tox]==0.2.15 pip install --user --upgrade setuptools # install Protobuf compiler - wget https://github.com/protocolbuffers/protobuf/releases/download/v3.19.4/protoc-3.19.4-linux-x86_64.zip - unzip protoc-3.19.4-linux-x86_64.zip -d protoc + wget https://github.com/protocolbuffers/protobuf/releases/download/v24.3/protoc-24.3-linux-x86_64.zip + unzip protoc-24.3-linux-x86_64.zip -d protoc sudo mv protoc/bin/protoc /usr/local/bin/protoc # install IPFS diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 9112d4f2e5..8ee6c42344 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -81,8 +81,8 @@ jobs: autonomy init --reset --author valory --ipfs --remote autonomy push-all - publish-images: - name: Publish Docker Images + publish-docs-images: + name: Publish Docs Images runs-on: ${{ matrix.os }} strategy: matrix: @@ -92,44 +92,102 @@ jobs: - publish-autonomy-packages steps: - uses: actions/checkout@v2 - - name: Set up tag - run: echo export TAG=$(python3 -c "from setup import about; print(about[\"__version__\"])") > env.sh - - name: Build version tagged images - run: | - source env.sh - docker build -t valory/open-autonomy-docs:$TAG -f deployments/Dockerfiles/documentation/Dockerfile . && \ - docker build -t valory/open-autonomy:$TAG deployments/Dockerfiles/autonomy && \ - docker build -t valory/open-autonomy-tendermint:$TAG deployments/Dockerfiles/tendermint && \ - docker build -t valory/open-autonomy-hardhat:$TAG deployments/Dockerfiles/hardhat && \ - docker build -t valory/open-autonomy-user:$TAG deployments/Dockerfiles/autonomy-user - - name: Tag to latest - run: | - source env.sh - docker tag valory/open-autonomy-docs:$TAG valory/open-autonomy-docs:latest - docker tag valory/open-autonomy:$TAG valory/open-autonomy:latest - docker tag valory/open-autonomy-tendermint:$TAG valory/open-autonomy-tendermint:latest - docker tag valory/open-autonomy-hardhat:$TAG valory/open-autonomy-hardhat:latest - docker tag valory/open-autonomy-user:$TAG valory/open-autonomy-user:latest - name: Docker login env: DOCKER_USER: ${{secrets.DOCKER_USER}} DOCKER_PASSWORD: ${{secrets.DOCKER_PASSWORD}} run: | docker login -u $DOCKER_USER -p $DOCKER_PASSWORD - - name: Docker Push + - name: Set up tag + run: echo export TAG=$(python3 -c "from setup import about; print(about[\"__version__\"])") > env.sh + - name: Build version tagged images run: | source env.sh - docker push valory/open-autonomy-docs:$TAG - docker push valory/open-autonomy-docs:latest - - docker push valory/open-autonomy:$TAG - docker push valory/open-autonomy:latest - - docker push valory/open-autonomy-tendermint:$TAG - docker push valory/open-autonomy-tendermint:latest - - docker push valory/open-autonomy-hardhat:$TAG - docker push valory/open-autonomy-hardhat:latest - - docker push valory/open-autonomy-user:$TAG - docker push valory/open-autonomy-user:latest + docker build -t valory/open-autonomy-docs:$TAG -f deployments/Dockerfiles/documentation/Dockerfile . --push + docker build -t valory/open-autonomy-docs:latest -f deployments/Dockerfiles/documentation/Dockerfile . --push + + publish-deploy-images: + name: Publish Deploy Images + runs-on: ubuntu-latest + needs: + - publish-autonomy-packages + steps: + - uses: actions/checkout@v2 + - name: Docker login + env: + DOCKER_USER: ${{secrets.DOCKER_USER}} + DOCKER_PASSWORD: ${{secrets.DOCKER_PASSWORD}} + run: | + docker login -u $DOCKER_USER -p $DOCKER_PASSWORD + - name: Set up support for multi platform build + run: | + docker run --privileged --rm tonistiigi/binfmt --install all + docker buildx create --use --name multibuild + docker buildx inspect --bootstrap + - name: Set up tag + run: echo export TAG=$(python3 -c "from setup import about; print(about[\"__version__\"])") > env.sh + - name: Build and push version tagged images + run: | + # export `TAG` variable + source env.sh + docker buildx build --platform linux/amd64,linux/arm64,linux/arm/v7 -t valory/open-autonomy:$TAG deployments/Dockerfiles/autonomy --push + docker buildx build --platform linux/amd64,linux/arm64,linux/arm/v7 -t valory/open-autonomy:latest deployments/Dockerfiles/autonomy --push + + publish-user-images: + name: Publish User Images + runs-on: ubuntu-latest + needs: + - publish-autonomy-packages + steps: + - uses: actions/checkout@v2 + - name: Docker login + env: + DOCKER_USER: ${{secrets.DOCKER_USER}} + DOCKER_PASSWORD: ${{secrets.DOCKER_PASSWORD}} + run: | + docker login -u $DOCKER_USER -p $DOCKER_PASSWORD + - name: Set up support for multi platform build + run: | + docker run --privileged --rm tonistiigi/binfmt --install all + docker buildx create --use --name multibuild + docker buildx inspect --bootstrap + - name: Set up tag + run: echo export TAG=$(python3 -c "from setup import about; print(about[\"__version__\"])") > env.sh + - name: Build and push version tagged images + run: | + # export `TAG` variable + source env.sh + docker buildx build --platform linux/amd64,linux/arm64 -t valory/open-autonomy-user:$TAG deployments/Dockerfiles/autonomy-user --push + docker buildx build --platform linux/amd64,linux/arm64 -t valory/open-autonomy-user:latest deployments/Dockerfiles/autonomy-user --push + + publish-helper-images: + name: Publish Helper Images + runs-on: ubuntu-latest + needs: + - publish-autonomy-packages + steps: + - uses: actions/checkout@v2 + - name: Docker login + env: + DOCKER_USER: ${{secrets.DOCKER_USER}} + DOCKER_PASSWORD: ${{secrets.DOCKER_PASSWORD}} + run: | + docker login -u $DOCKER_USER -p $DOCKER_PASSWORD + - name: Set up support for multi platform build + run: | + docker run --privileged --rm tonistiigi/binfmt --install all + docker buildx create --use --name multibuild + docker buildx inspect --bootstrap + - name: Set up tag + run: echo export TAG=$(python3 -c "from setup import about; print(about[\"__version__\"])") > env.sh + - name: Build and push version tagged images + run: | + # export `TAG` variable + source env.sh + + docker buildx build --platform linux/amd64,linux/arm64,linux/arm/v7 -t valory/open-autonomy-tendermint:$TAG deployments/Dockerfiles/tendermint --push + docker buildx build --platform linux/amd64,linux/arm64,linux/arm/v7 -t valory/open-autonomy-tendermint:latest deployments/Dockerfiles/tendermint --push + + docker buildx build --platform linux/amd64,linux/arm64 -t valory/open-autonomy-hardhat:$TAG deployments/Dockerfiles/hardhat --push + docker buildx build --platform linux/amd64,linux/arm64 -t valory/open-autonomy-hardhat:latest deployments/Dockerfiles/hardhat --push + diff --git a/.gitignore b/.gitignore index 7167e2a33a..488dae5995 100644 --- a/.gitignore +++ b/.gitignore @@ -389,6 +389,8 @@ Pipfile.lock !packages/valory/contracts/component_registry/build !packages/valory/contracts/agent_registry/build !packages/valory/contracts/service_manager/build +!packages/valory/contracts/erc20/build +!packages/valory/contracts/service_registry_token_utility/build packages/open_aea @@ -401,11 +403,16 @@ packages/valory/protocols/contract_api packages/valory/protocols/http packages/valory/protocols/ledger_api -autonomy/data/contracts/registries_manager -autonomy/data/contracts/component_registry -autonomy/data/contracts/service_registry autonomy/data/contracts/agent_registry +autonomy/data/contracts/component_registry +autonomy/data/contracts/erc20 +autonomy/data/contracts/gnosis_safe +autonomy/data/contracts/gnosis_safe_proxy_factory +autonomy/data/contracts/multisend +autonomy/data/contracts/registries_manager autonomy/data/contracts/service_manager +autonomy/data/contracts/service_registry +autonomy/data/contracts/service_registry_token_utility .vscode/ @@ -416,4 +423,6 @@ keys.json leak_report temp/ -logs.db \ No newline at end of file +logs.db +benchmarks.html +agent/ \ No newline at end of file diff --git a/.pylintrc b/.pylintrc new file mode 100644 index 0000000000..245ae911c7 --- /dev/null +++ b/.pylintrc @@ -0,0 +1,59 @@ +[MASTER] +ignore-patterns=.*_pb2.py,contract_dispatcher.py,test_abci_messages.py,test_tendermint_messages.py +ignore=packages/valory/protocols/abci,packages/valory/connections/abci/gogoproto + +[MESSAGES CONTROL] +disable=C0103,R0801,C0301,C0201,C0204,C0209,W1203,C0302,R1735,R1729,W0511,E0611 + +# See here for more options: https://www.codeac.io/documentation/pylint-configuration.html +R1735: use-dict-literal +R1729: use-a-generator +C0103: invalid-name +C0201: consider-iterating-dictionary +W1203: logging-fstring-interpolation +C0204: bad-mcs-classmethod-argument +C0209: consider-using-f-string +C0301: http://pylint-messages.wikidot.com/messages:c0301 > Line too long +C0302: http://pylint-messages.wikidot.com/messages:c0302 > Too many lines in module +R0801: similar lines +E0611: no-name-in-module + +[IMPORTS] +ignored-modules=pandas,numpy,aea_cli_ipfs,compose,multidict + +[DESIGN] +# min-public-methods=1 +max-public-methods=58 +# max-returns=10 +# max-bool-expr=7 +max-args=6 +# max-locals=31 +# max-statements=80 +max-parents=10 +max-branches=36 +max-attributes=8 + +[REFACTORING] +# max-nested-blocks=6 + +[SPELLING] +# uncomment to enable +# spelling-dict=en_US + +# List of comma separated words that should not be checked. +spelling-ignore-words=nocover,pragma,params,noqa,kwargs,str,async,json,boolean,config,pytest,args,url,tx,jsonschema,traceback,api,nosec + +[SIMILARITIES] + +# Minimum lines number of a similarity. +min-similarity-lines=10 + +# Ignore comments when computing similarities. +ignore-comments=yes + +# Ignore docstrings when computing similarities. +ignore-docstrings=yes + +# Ignore imports when computing similarities. +ignore-imports=no + diff --git a/.spelling b/.spelling index 3d0c2f55c4..8b35e450cc 100644 --- a/.spelling +++ b/.spelling @@ -3,6 +3,8 @@ # global dictionary is at the start, file overrides afterwards # one word per line, to define a file override use ' - filename' # where filename is relative to this configuration file +tomte +0.10.11.post1 anymore AEAs Tendermint @@ -19,6 +21,7 @@ ABCI-compatible Fantom ABCI-application mixin +minikube startup standalone FIPA-like @@ -336,6 +339,8 @@ serializer 0.2.1.post1 0.5.0.post1 0.5.0.post2 +0.10.5.post1 +0.10.5.post2 shebangs - docs/control_flow.md EntryPoint @@ -411,4 +416,14 @@ my_fsm_app_skill fuzzer selection_key 0.10.0.post1 -0.10.0.post2 \ No newline at end of file +0.10.0.post2 +0.10.10.post1 +unbond +chiado +0.12.1.post1 +0.12.1.post2 +0.12.1.post3 +0.12.1.post4 +0.13.1.post1 +0.13.9.post1 +i \ No newline at end of file diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index f6c204cc87..dc308896bc 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -15,8 +15,8 @@ Also mention potential effects on other branches/code might have from your chang For a clean workflow run checks in following order before making a PR or pushing the code - make clean -- make formatters -- make code-checks +- tomte format-code +- tomte check-code - make security **Run only if you've modified an AbciApp definition** @@ -53,7 +53,7 @@ def some_method(some_arg: Type) -> ReturnType: """ ``` - To run documentation server use `mkdocs serve`. -- After editing documentation use `./scripts/spell-check.sh` to ensure spelling is correct. +- After editing documentation use `tomte check-spelling` to ensure spelling is correct. ### Some more suggestions to help you write better code. diff --git a/HISTORY.md b/HISTORY.md index 0130a5a594..a24d5b69bc 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -1,5 +1,306 @@ # Release History - `open-autonomy` +# 0.13.9.post1 (2023-12-26) + +- Bumps `open-aea@1.43.0.post2` + +# 0.13.9 (2023-12-19) + +Autonomy: +- Updates the tendermint image to support arm platforms +- Updates the autonomy image to use `--timeout` flag on `aea install` command to avoid timeout failures on machines with limited resources + +Docs: +- Fixes `hello-world` hash in the quick start guide +- Adds requirements for developing and running on `raspberry-pi` + +# 0.13.8 (2023-11-30) + +Autonomy: +- Implements transaction settlement on the `mint/service` command groups + - Adds support for retrying transaction on known error + - Adds support for repricing under priced transactions +- Adds support for performing dry-run on on-chain interaction tools + +Chore: +- Adds a script for bumping services + +# 0.13.7 (2023-11-23) + +Autonomy: +- Adds support for logging to console on tendermint server + +# 0.13.6 (2023-11-21) + +Autonomy: +- Fixes the start.sh script to use password if provided when issuing certificates + +Packages: +- Renames the `chain_name` parameter to `chain_id` on transaction settlement skill + +Docs: +- Updates the documentation on private key security in deployments + +# 0.13.5 (2023-11-14) + +Autonomy: +- Pins `protobuf<4.25.0,>=4.21.6` + +Packages: +- Ports changes on transaction settlement skill from `IEKit` and `agent-academy-2` +- Updates the transaction settlement ABCI to handle safe-nonce reuse + +# 0.13.4 (2023-11-01) + +Autonomy: +- Updates the mint tools to propagate `token` address to update service transactions + +# 0.13.3 (2023-11-01) + +- Synchronises the `on-chain` addresses with the latest protocol release + +# 0.13.2 (2023-10-30) + +- Adds support for specifying custom `Dockerfile` for building agent images +- Deprecates `--password` flag on `autonomy deploy build/from-token` commands +- Introduces `OPEN_AUTONOMY_PRIVATE_KEY_PASSWORD` as environment variable for providing private key passwords to deployments +- Updates the service analyser to skip `abci` connection since it's not required to be manually overridden + +# 0.13.1.post1 (2023-10-24) + +Chore: +- Bumps `open-aea@1.41.0.post1` + +# 0.13.1 (2023-10-11) + +Autonomy: +- Updates the on-chain tools to use service manager token contract for managing services on gnosis +- Makes fallback handler address configurable when deploying a service +- Updates the log parser to use `utf-8` encoding to avoid decoding issues on windows +- Fixes the log parser multiline parsing +- Fixes the deployment exits on windows +- Updates error handling for invalid private keys +- Fixes error messages for unreferenced events in the FSM check +- Updates the environment variable validation to + - Validate data type + - Validate default value +- Updates the service analyser to warn if the termination skill or the slashing skill is missing as a dependency +- Adds support for service level dependencies + +Packages: +- Moves the hypothesis imports to test modules to avoid import errors at runtime +- Removes the hello world service + +# 0.13.0 (2023-09-27) + +Autonomy: +- Replaces `open-aea-web3` with `web3py<7,>=6.0.0` +- Bumps `protobuf<5.0.0,>=4.21.6` +- Fixes `protobuf` incompatibility issue when importing hardware wallet plugin +- Refactors autonomy and agent images to + - Include install and build scripts in the base image + - Remove unwanted layers + - Remove unwanted data files + +Packages: +- Generates protocols using the latest compatible `protobuf` compiler +- Compiles the tendermint connection protocol buffers using the latest compatible `protobuf` compiler + +Chores: +- Bumps `protobuf` compiler to `24.3` + +# 0.12.1.post4 (2023-09-25) + +Autonomy: + +- Update the reuse multisig transaction builder to account for services with only one operator + +# 0.12.1.post3 (2023-09-21) + +Autonomy: + +- Pins `jsonschema<=4.19.0,>=4.16.0` + +# 0.12.1.post2 (2023-09-20) + +Autonomy: + +- Adds missing contract packages to the `eject-contracts` make target +- Adds check to make sure service is in `pre-registration` before updating the service hash +- Adds check to make sure all required environment variables are present for on-chain interactions + +# 0.12.1.post1 (2023-09-14) + +Autonomy: + +- Pin `hexbytes` as framework dependency + +# 0.12.1 (2023-09-12) + +Autonomy: + +- Adds support for updating already minted components with latest hashes +- Adds support for using ERC20 tokens for securing autonomous services +- Adds support for reusing the same multisig for on-chain service redeployment + +Docs: +- Updates documentation for the latest features +- Adds a list of addresses across various chains in documentation + +# 0.12.0 (2023-08-24) + +Autonomy: +- Fixes deployment build bug on windows #2039 + +Packages: +- Adds slashing functionality #1927 +- Adds support for checking the safe nonce before re-sending a transaction #2040 + +# 0.11.1 (2023-08-18) + +Autonomy: +- Adds support for `arm/v7` docker images +- Adds support for running the service in background using `--detach` flag in the `autonomy deploy run` command +- Adds support for stopping the service running in background using `autonomy deploy stop` +- Implements clean exists from `docker-compose` deployments + +Packages: +- Reverts #1996, because it introduced some instability + +# 0.11.0 (2023-08-14) + +Autonomy: +- Deprecates the support for `Python 3.7` and extends support for `Python 3.11` +- Adds support for multi platform image builds + +Packages: +- Replaces the usage of deprecated `web3py` APIs + +Chore: +- Replaces the `web3py` with `open-aea-web3` +- Bumps `py-ecc@6.0.0`, `numpy@>=1.21.6` and `pandas@1.5.3` + +# 0.10.11.post1 (2023-08-10) + +Autonomy: +- Fixes the deployment payload calculations on `autonomy service deploy` command + +# 0.10.11 (2023-08-08) + +Autonomy: +- Adds support for minting services on layer 2 chains +- Adds support for skipping dependency checks when minting components + +# 0.10.10.post1 (2023-07-28) + +Autonomy: +- Update `tendermint` testnet command generator to accommodate for new container naming format + +# 0.10.10 (2023-07-26) + +Autonomy: +- Adds support for running multiple `docker-compose` deployments in the same machine + + +# 0.10.9 (2023-07-25) + +Autonomy: +- Bumps `open-aea` to `v1.37.0` + + +# 0.10.8 (2023-07-19) + +Autonomy: + - open-aea bumped to 1.36.0 + +# 0.10.7 (2023-06-21) + +Packages: +- Make sure the timeout gets checked even when there's no message from connection #1996 +- Fixes the gentle reset logic #2000 +- Refactors the block stall tolerance as it was not large enough for edge cases #2002 + +Chore: +- Bumps `web3py` to `v5.31.4` #1999 + +Docs: +- Fixes `olas.network` links #1998 + +# 0.10.6 (2023-06-12) + +Autonomy: +- Makes the chained `ABCI` skill filter more strict on the service analyser #1982 + +Packages: +- Fixes the gentle reset logic #1987 + +Docs: +- Fixes code check linter #1986 + +# 0.10.5.post2 (2023-06-06) + +Autonomy: +- Update agent node template on the kubernetes generator to support different types of private keys from various ledgers #1991 + + +# 0.10.5.post1 (2023-05-24) + +Autonomy: +- Makes sure the alias gets used when fetching service packages #1947 +- Updates the agent runtime docker image to execute aea build when building the runtime image #1954 +- Adds support for `terminate` and `unbond` actions on `autonomy service` command group #1956 +- Generalises the `star.sh` script on the autonomy runtime docker image to deal with different types of keys #1964 +- Makes ledger plugins optional for CLI tools #1973 +- Adds support for loading environment variables from file on the `autonomy deploy` command group #1960 + +Packages: +- Addresses Tendermint disconnection issues. #1976 + +Plugins: +- Removes the hardware wallet plugin as a dependency from contract packages #1973 +- Fixes the ledger plugin version specifiers on the test plugin #197 + +Chores: +- Pins `typing_extensions` to `>=3.10.0.2` to avoid dependency conflicts with `solana` plugin #1964 +- Bumps docker to `v6.1.2` #1975 + +Docs: +- Adds information on required agent components #1967 + +# 0.10.4 (2023-05-11) + +Autonomy: +- Adds support for exposing `tendermint` container ports on the docker compose deployments #1952 + +Packages: +- Removes the kill logic in case the active Tendermint peers are less than the majority of the participants #1958 +- Adds support for verifying the service registry on Polygon and Gnosis #1959 +- Improves error logging during registration #1961 + +Docs: +- Updates deployment guide for the cluster deployments #1924 + +Docs: +- Improves cluster deployment section, now based on minikube #1924 + +# 0.10.3 (2023-05-03) + +Autonomy: +- Updates the FSM scaffold tool to add downloaded packages to `third_party` packages #1943 +- Improves the service specification analyser #1942 + - Implements custom schema validator to report all validation issues at once + - Adds support for skip warnings + - Raises warning when components are defined in the agent config and not in the service config + - Adds support for validating environment overrides + - Improves error messages + +Docs: +- Adds auto-correcting functionality for several package hash instances #1939 +- Fixes port mapping documentation #1944 + +Chores: +- Adds service analysis to workflow #1942 + # 0.10.2 (2023-04-24) Autonomy: diff --git a/Makefile b/Makefile index 5556084e64..e76cf4a92d 100644 --- a/Makefile +++ b/Makefile @@ -44,28 +44,10 @@ clean-test: clean-cache # removes various cache files .PHONY: clean-cache clean-cache: - rm -fr .hypothesis/ + find . -type d -name .hypothesis -prune -exec rm -rf {} \; rm -fr .pytest_cache rm -fr .mypy_cache/ -# isort: fix import orders -# black: format files according to the pep standards -.PHONY: formatters -formatters: - tox -e isort - tox -e black - -# black-check: check code style -# isort-check: check for import order -# flake8: wrapper around various code checks, https://flake8.pycqa.org/en/latest/user/error-codes.html -# mypy: static type checker -# pylint: code analysis for code smells and refactoring suggestions -# vulture: finds dead code -# darglint: docstring linter -.PHONY: code-checks -code-checks: - tox -p -e black-check -e isort-check -e flake8 -e mypy -e pylint -e vulture -e darglint - # safety: checks dependencies for known security vulnerabilities # bandit: security linter .PHONY: security @@ -109,7 +91,7 @@ test: find . -name ".coverage*" -not -name ".coveragerc" -exec rm -fr "{}" \; .PHONY: all-checks -all-checks: clean formatters code-checks security generators common-checks-1 common-checks-2 +all-checks: clean security generators common-checks-1 common-checks-2 .PHONY: test-skill test-skill: @@ -148,7 +130,7 @@ install: clean .PHONY: eject-contracts eject-contracts: - @for contract in registries_manager service_manager component_registry agent_registry service_registry ; do \ + @for contract in component_registry agent_registry registries_manager service_manager service_registry gnosis_safe gnosis_safe_proxy_factory service_registry_token_utility multisend erc20 ; do \ echo Updating $$contract contract; \ rm -rf autonomy/data/contracts/$$contract ; \ cp -r packages/valory/contracts/$$contract autonomy/data/contracts/$$contract ; \ @@ -205,8 +187,22 @@ run-hardhat: docker run -p 8545:8545 -it valory/open-autonomy-hardhat:0.1.0 protolint_install: - GO111MODULE=on GOPATH=~/go go get -u -v github.com/yoheimuta/protolint/cmd/protolint@v0.27.0 - + mkdir protolint_install + cd protolint_install && \ + wget https://github.com/yoheimuta/protolint/releases/download/v0.27.0/protolint_0.27.0_Linux_x86_64.tar.gz && \ + tar -xvf protolint_0.27.0_Linux_x86_64.tar.gz && \ + sudo mv protolint /usr/local/bin/protolint + sudo rm -rf protolint_install + +protolint_install_darwin: + mkdir protolint_install + cd protolint_install && \ + wget https://github.com/yoheimuta/protolint/releases/download/v0.27.0/protolint_0.27.0_Darwin_x86_64.tar.gz && \ + tar -xvf protolint_0.27.0_Darwin_x86_64.tar.gz && \ + sudo mv protolint /usr/local/bin/protolint + sudo rm -rf protolint_install + +# TODO: use precompiled binary protolint_install_win: powershell -command '$$env:GO111MODULE="on"; go install github.com/yoheimuta/protolint/cmd/protolint@v0.27.0' @@ -233,9 +229,25 @@ fix-abci-app-specs: autonomy analyse fsm-specs --update --app-class AgentRegistrationAbciApp --package packages/valory/skills/registration_abci || (echo "Failed to check registration_abci consistency" && exit 1) autonomy analyse fsm-specs --update --app-class ResetPauseAbciApp --package packages/valory/skills/reset_pause_abci || (echo "Failed to check reset_pause_abci consistency" && exit 1) autonomy analyse fsm-specs --update --app-class RegisterResetAbciApp --package packages/valory/skills/register_reset_abci || (echo "Failed to check register_reset_abci consistency" && exit 1) - autonomy analyse fsm-specs --update --app-class HelloWorldAbciApp --package packages/valory/skills/hello_world_abci || (echo "Failed to check hello_world_abci consistency" && exit 1) autonomy analyse fsm-specs --update --app-class TransactionSubmissionAbciApp --package packages/valory/skills/transaction_settlement_abci || (echo "Failed to check transaction_settlement_abci consistency" && exit 1) + autonomy analyse fsm-specs --update --app-class OffendAbciApp --package packages/valory/skills/offend_abci || (echo "Failed to check offend_abci consistency" && exit 1) echo "Successfully validated abcis!" release-images: skaffold build -p release --cache-artifacts=false && skaffold build -p release-latest + + +# Usage: INCLUDE=PATH_TO_PROTOC_INCLUDE_DIRECTORY make build-proto +.PHONY: build-proto +build-proto: + @protoc -I $$INCLUDE \ + --proto_path=packages/valory/connections/abci/protos/ \ + --python_out=packages/valory/connections/abci/ \ + packages/valory/connections/abci/protos/gogoproto/gogo.proto \ + packages/valory/connections/abci/protos/tendermint/crypto/proof.proto \ + packages/valory/connections/abci/protos/tendermint/crypto/keys.proto \ + packages/valory/connections/abci/protos/tendermint/abci/types.proto \ + packages/valory/connections/abci/protos/tendermint/types/types.proto \ + packages/valory/connections/abci/protos/tendermint/types/validator.proto \ + packages/valory/connections/abci/protos/tendermint/types/params.proto \ + packages/valory/connections/abci/protos/tendermint/version/types.proto \ No newline at end of file diff --git a/Pipfile b/Pipfile index 69bf203754..887272111e 100644 --- a/Pipfile +++ b/Pipfile @@ -4,35 +4,53 @@ verify_ssl = true name = "pypi" [packages] -docker = "==6.0.0" -docker-compose = "==1.29.2" +aiohttp = "<4.0.0,>=3.8.5" +docker = "==6.1.2" Flask = "==2.0.2" -open-aea = {version = "==1.32.0", extras = ["all"]} -open-aea-ledger-ethereum = "==1.32.0" -open-aea-ledger-ethereum-hwi = "==1.32.0" -open-aea-cli-ipfs = "==1.32.0" +open-aea = {version = "==1.43.0.post2", extras = ["all"]} +open-aea-ledger-ethereum = "==1.43.0.post2" +open-aea-ledger-ethereum-hwi = "==1.43.0.post2" +open-aea-cli-ipfs = "==1.43.0.post2" +ipfshttpclient = "==0.8.0a2" Werkzeug= "==2.0.3" -gql = "==3.4.0" +watchdog = ">=2.1.6" +pytest = "==7.2.1" +click = "==8.0.2" +valory-docker-compose = "==1.29.3" [dev-packages] ### package deps -aiohttp = "==3.7.4.post0" -asn1crypto = "==1.4.0" +aiohttp = "<4.0.0,>=3.8.5" +asn1crypto = "<1.5.0,>=1.4.0" +ecdsa = ">=0.15" +web3 = "<7,>=6.0.0" +certifi = "*" +multidict = "*" +eth_typing ="*" +eth-account = ">=0.8.0,<0.9.0" +typing_extensions = ">=3.10.0.2" +hexbytes = "*" +packaging = "*" +pytest-asyncio = "*" +open-aea-ledger-cosmos = "==1.43.0.post2" # we pin this as the range specified in open-aea-ledger-cosmos is wide -cosmpy = "==0.3.1" -grpcio = "==1.43.0" +open-aea-cosmpy = "==0.6.7" +grpcio = "==1.53.0" hypothesis = "==6.21.6" # latest supported for Python 3.7 -numpy = "==1.21.6" -open-aea-ledger-cosmos = "==1.32.0" -pandas = "==1.3.5" -pandas-stubs = "==1.2.0.62" -protobuf = ">=3.20,<=3.20.1" +protobuf = "<4.25.0,>=4.21.6" pytz = "==2022.2.1" -py-ecc = "==5.2.0" -py-eth-sig-utils = "==0.4.0" +py-ecc = "==6.0.0" +python-dotenv = ">=0.14.0,<0.18.0" +requests = "==2.28.1" ### tests deps -tomte = {version = "==0.2.4", extras = ["tox", "tests"]} +tomte = {version = "==0.2.15", extras = ["tests", "cli"]} +texttable = "==1.6.7" +toml = "==0.10.2" +eth-utils = "==2.2.0" +eth-abi = "==4.0.0" +pycryptodome = "==3.18.0" +jsonschema = "<4.4.0,>=4.3.0" [requires] python_version = "3.10" diff --git a/README.md b/README.md index c98b248459..5b7bd02cb4 100644 --- a/README.md +++ b/README.md @@ -57,11 +57,11 @@ Read the [Open Autonomy documentation](https://docs.autonolas.network/open-auton - Ensure your machine satisfies the following requirements: - - Python `>= 3.7` + - Python `>= 3.8` - [Tendermint](https://docs.tendermint.com/v0.34/introduction/install.html) `==0.34.19` - [IPFS node](https://docs.ipfs.io/install/command-line/#official-distributions) `==v0.6.0` - [Pip](https://pip.pypa.io/en/stable/installation/) - - [Pipenv](https://pipenv.pypa.io/en/latest/installation/) `>=2021.x.xx` + - [Pipenv](https://pipenv.pypa.io/en/latest/installation.html) `>=2021.x.xx` - [Go](https://go.dev/doc/install) `==1.17.7` - [Kubectl](https://kubernetes.io/docs/tasks/tools/) - [Docker Engine](https://docs.docker.com/engine/install/) diff --git a/SECURITY.md b/SECURITY.md index af0a9093aa..806d67c24a 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -8,8 +8,8 @@ The following table shows which versions of `open-autonomy` are currently being | Version | Supported | | --------- | ------------------ | -| `0.10.2` | :white_check_mark: | -| `< 0.10.2` | :x: | +| `0.13.9` | :white_check_mark: | +| `< 0.13.x` | :x: | ## Reporting a Vulnerability diff --git a/autonomy/__version__.py b/autonomy/__version__.py index 198feca440..f79baeece4 100644 --- a/autonomy/__version__.py +++ b/autonomy/__version__.py @@ -22,7 +22,7 @@ __title__ = "open-autonomy" __description__ = "A framework for the creation of autonomous agent services." __url__ = "https://github.com/valory-xyz/open-autonomy.git" -__version__ = "0.10.2" +__version__ = "0.13.9.post1" __author__ = "Valory AG" __license__ = "Apache-2.0" __copyright__ = "2021-2022 Valory AG" diff --git a/autonomy/analyse/abci/app_spec.py b/autonomy/analyse/abci/app_spec.py index 8fbcbe948e..73e8a87d99 100644 --- a/autonomy/analyse/abci/app_spec.py +++ b/autonomy/analyse/abci/app_spec.py @@ -45,6 +45,7 @@ ABCI_APP_CLASS_POST_FIX = "AbciApp" EVENT_PATTERN = re.compile(r"Event\.(\w+)", re.DOTALL) +ROUND_TIMEOUT_EVENTS = {"ROUND_TIMEOUT"} def validate_fsm_spec(data: Dict) -> None: @@ -454,14 +455,11 @@ def check_unreferenced_events(abci_app_cls: Any) -> List[str]: """ error_strings = [] - timeout_events = {k.name for k in abci_app_cls.event_to_timeout.keys()} + abci_app_timeout_events = {k.name for k in abci_app_cls.event_to_timeout.keys()} for round_cls, round_transitions in abci_app_cls.transition_function.items(): - trf_events = { - str(e).rsplit(".", 1)[1] for e in round_transitions - } - timeout_events + round_transition_events = set(map(lambda x: x.name, round_transitions)) referenced_events = set() - for base in filter( lambda x: x.__class__.__module__ != "builtins", inspect.getmro(round_cls), @@ -469,10 +467,21 @@ def check_unreferenced_events(abci_app_cls: Any) -> List[str]: src = textwrap.dedent(inspect.getsource(base)) referenced_events.update(EVENT_PATTERN.findall(src)) - if trf_events.symmetric_difference(referenced_events): + # Referenced in the the class definition, missing from transition func + missing_from_transition_func = referenced_events - round_transition_events + if len(missing_from_transition_func) > 0: + error_strings.append( + f"Events {missing_from_transition_func} are present in the `{round_cls.__name__}` " + f"but missing from transition function" + ) + + # Filter timeout events using referenced events since we don't explicitly return the timeout events + timeout_events = round_transition_events - referenced_events + missing_timeout_events = timeout_events - abci_app_timeout_events + if len(missing_timeout_events) > 0: error_strings.append( - f" - {round_cls.__name__}: transition function events {trf_events} " - f"do not match referenced events {referenced_events}." + f"Events {missing_timeout_events} are defined in the round transitions of `{round_cls.__name__}` " + f"but not in `event_to_timeout`" ) return error_strings diff --git a/autonomy/analyse/benchmark/aggregate.py b/autonomy/analyse/benchmark/aggregate.py index d2c51204e8..7fad25af28 100644 --- a/autonomy/analyse/benchmark/aggregate.py +++ b/autonomy/analyse/benchmark/aggregate.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- # ------------------------------------------------------------------------------ # -# Copyright 2021-2022 Valory AG +# Copyright 2021-2023 Valory AG # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -20,12 +20,25 @@ """Tools for aggregating benchmark results.""" import json +import statistics from pathlib import Path -from typing import Any, Dict, List +from typing import Callable, Dict, List, Tuple, cast -import pandas as pd +from autonomy.analyse.benchmark.html import ( + BLOCK_TEMPLATE, + HTML_TEMPLATE, + TABLE_TEMPLATE, + TD_TEMPLATE, + TH_TEMPLATE, + TROW_TEMPLATE, +) -from autonomy.analyse.benchmark.html import HTML_TEMPLATE, TABLE_TEMPLATE + +STATISTICS = { + "Mean": statistics.mean, + "Maximum": max, + "Minimum": min, +} class BlockTypes: # pylint: disable=too-few-public-methods @@ -39,95 +52,149 @@ class BlockTypes: # pylint: disable=too-few-public-methods types = (LOCAL, CONSENSUS, TOTAL) -def read_benchmark_data(path: Path) -> List[Dict]: +def read_benchmark_data( + path: Path, + block_type: str = BlockTypes.ALL, + period: int = -1, +) -> Dict[str, Dict[str, List[Dict]]]: """Returns logs.""" - benchmark_data = [] + benchmark_data: Dict[str, Dict[str, List[Dict]]] = {} for agent_dir in path.iterdir(): - agent_benchmark_data: Dict[str, Any] = {} - agent_benchmark_data["name"] = agent_dir.name - agent_benchmark_data["data"] = dict( - map( - lambda path: ( - int(path.name.replace(".json", "")), - json.loads(path.read_text()), - ), - agent_dir.glob("*.json"), - ) + benchmark_data[agent_dir.name] = {} + benchmark_data_files = list(agent_dir.glob("*.json")) + periods = sorted( + tuple(map(lambda x: x.name, benchmark_data_files)) + if period == -1 + else (f"{period}.json",) ) - benchmark_data.append(agent_benchmark_data) - return benchmark_data - - -def create_dataframe(data: List[Dict]) -> pd.DataFrame: - """Create pandas.DataFrame object from benchmark data.""" - - rows = [] - behaviours = [behaviour_data["behaviour"] for behaviour_data in data[0]["data"][0]] - cols = ["agent", "period", "block_type", *behaviours] - - for agent in data: - for period_n, period_data in agent["data"].items(): - for block_t in BlockTypes.types: - rows.append( - { - "agent": agent["name"], - "period": period_n, - "block_type": block_t, - **{ - behaviour_data["behaviour"]: behaviour_data["data"].get( - block_t, 0.0 - ) - for behaviour_data in period_data - }, - } - ) + for _period in periods: + period_name, _ = _period.split(".") + period_data = json.loads((agent_dir / _period).read_text()) + if block_type == BlockTypes.ALL: + benchmark_data[agent_dir.name][period_name] = period_data + continue + + benchmark_data[agent_dir.name][period_name] = [ + { + "behaviour": behaviour["behaviour"], + "data": {block_type: behaviour["data"][block_type]}, + } + for behaviour in period_data + ] - return pd.DataFrame( - data=rows, - )[cols] - - -def format_output(df: pd.DataFrame, period: int, block_type: str) -> str: - """Format output from given dataframe and parameters""" - - df = df.copy(deep=True).fillna(value=0.0) - df = df[df["period"] == period] - df = df[df["block_type"] == block_type] + return benchmark_data - del df["period"] - del df["block_type"] - time_df = df[df.columns[1:]] - stats_df = pd.DataFrame( - data=[ - ["mean", *time_df.mean().values], - ["median", *time_df.median().values], - ["std_dev", *time_df.std().values], - ], - columns=df.columns, +def add_statistic( + name: str, + aggregator: Callable, + behaviours: List[str], + behaviour_history: Dict[str, List[float]], +) -> str: + """Add a stastic column.""" + rows = TD_TEMPLATE.format(name) + for behaviour in behaviours: + rows += TD_TEMPLATE.format(aggregator(behaviour_history[behaviour])) + return TROW_TEMPLATE.format(rows) + + +def add_statistics( + behaviours: List[str], + behaviour_history: Dict[str, List[float]], +) -> str: + """Add statistics.""" + tbody = TROW_TEMPLATE.format( + f"""Statistics""" ) - - output_df = pd.concat((df, stats_df)) - return output_df.to_html(index=False, justify="left") + for name, aggregator in STATISTICS.items(): + tbody += add_statistic( + name=name, + aggregator=cast(Callable, aggregator), + behaviour_history=behaviour_history, + behaviours=behaviours, + ) + return tbody + + +def create_table_data( + data: Dict[str, List[Dict]], + blocks: Tuple[str, ...], +) -> Tuple[List[str], List[str], Dict[str, Dict]]: + """Create table data.""" + periods: List[str] = [] + header_columns: List[str] = ["Period"] + tables_data: Dict[str, Dict] = {} + for block in blocks: + if block not in tables_data: + tables_data[block] = {} + for period, behaviours in data.items(): + for behaviour in behaviours: + if period not in tables_data[block]: + tables_data[block][period] = {} + tables_data[block][period][behaviour["behaviour"]] = behaviour["data"][ + block + ] + if behaviour["behaviour"] not in header_columns: + header_columns.append(behaviour["behaviour"]) + if period not in periods: + periods.append(period) + return periods, header_columns, tables_data + + +def create_agent_table( + agent: str, data: Dict[str, List[Dict]], blocks: Tuple[str, ...] +) -> str: + """Create agent table.""" + tables = f"""
Benchmark data for agent {agent}
\n""" + periods, header_columns, tables_data = create_table_data( + data=data, + blocks=blocks, + ) + behaviour_history: Dict[str, List[float]] = { + behaviour: [] for behaviour in header_columns[1:] + } + for block, block_data in tables_data.items(): + thead = "".join(map(TH_TEMPLATE.format, header_columns)) + tbody = "" + for period in sorted(periods): + rows = TD_TEMPLATE.format(period) + for behaviour_name in header_columns[1:]: + behaviour_history[behaviour_name].append( + block_data[period][behaviour_name] + ) + rows += TD_TEMPLATE.format(block_data[period][behaviour_name]) + tbody += TROW_TEMPLATE.format(rows) + tbody += add_statistics( + behaviours=header_columns[1:], behaviour_history=behaviour_history + ) + tables += BLOCK_TEMPLATE.format( + table=TABLE_TEMPLATE.format( + colspan=len(header_columns), + block_type=block, + thead=thead, + tbody=tbody, + ), + ) + return tables def aggregate(path: Path, block_type: str, period: int, output: Path) -> None: """Benchmark Aggregator.""" - path = Path(path) - benchmark_data = read_benchmark_data(path) - dataframe = create_dataframe(benchmark_data) - - periods = range(dataframe.period.max()) if period == -1 else (period,) - blocks = BlockTypes.types if block_type == BlockTypes.ALL else (block_type,) - - tables = "" - for period_n in periods: - for block_t in blocks: - tables += TABLE_TEMPLATE.format( - table=format_output(dataframe, period_n, block_t), - period=period_n, - block=block_t, - ) - - output.write_text(HTML_TEMPLATE.format(tables=tables), encoding="utf-8") + benchmark_data = read_benchmark_data( + path, + block_type=block_type, + period=period, + ) + tables = [ + create_agent_table( + agent=agent, + data=data, + blocks=( + BlockTypes.types if block_type == BlockTypes.ALL else (block_type,) + ), + ) + for agent, data in benchmark_data.items() + ] + + output.write_text(HTML_TEMPLATE.format(tables="".join(tables)), encoding="utf-8") diff --git a/autonomy/analyse/benchmark/html.py b/autonomy/analyse/benchmark/html.py index aeaf5032d0..fe73ef2620 100644 --- a/autonomy/analyse/benchmark/html.py +++ b/autonomy/analyse/benchmark/html.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- # ------------------------------------------------------------------------------ # -# Copyright 2022 Valory AG +# Copyright 2022-2023 Valory AG # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -54,10 +54,28 @@ """ +BLOCK_TEMPLATE = """ +
+ {table} +
""" + TABLE_TEMPLATE = """ -
-
- Period: {period} | Block: {block} -
- {table} -
""" + + + + + {thead} + {tbody} +
Block: {block_type}
""" + +TROW_TEMPLATE = """ + +{} + +""" + +TH_TEMPLATE = """ + {}""" + +TD_TEMPLATE = """ + {}""" diff --git a/autonomy/analyse/logs/base.py b/autonomy/analyse/logs/base.py index 7fb822e07f..276a4b7c70 100644 --- a/autonomy/analyse/logs/base.py +++ b/autonomy/analyse/logs/base.py @@ -29,7 +29,7 @@ TIME_FORMAT = "%Y-%m-%d %H:%M:%S,%f" TIMESTAMP_REGEX = re.compile(r"^(\[(\d+-\d+-\d+ \d+:\d+:\d+,\d+)\])") LOG_ROW_REGEX = re.compile( - r"\[(\d+-\d+-\d+ \d+:\d+:\d+,\d+)\] \[([A-Z]+)\]( \[agent\])? (.*)" + r"\[(\d+-\d+-\d+ \d+:\d+:\d+,\d+)\] \[([A-Z]+)\]( \[agent\])? ((.|\n)*)" ) ENTER_BEHAVIOUR_REGEX = re.compile(r"Entered in the \'([a-z_]+)\' behaviour") ENTER_ROUND_REGEX = re.compile(r"Entered in the \'([a-z_]+)\' round for period (\d+)") diff --git a/autonomy/analyse/logs/collection.py b/autonomy/analyse/logs/collection.py index d152601fbc..cc048fe187 100644 --- a/autonomy/analyse/logs/collection.py +++ b/autonomy/analyse/logs/collection.py @@ -61,38 +61,38 @@ def create_agent_db( @staticmethod def get_next_log_block( - fp: TextIO, prev_line: str + fp: TextIO, + prev_line: Optional[str], ) -> Tuple[Optional[str], Optional[str]]: """Get next log block.""" + if prev_line is None: + return None, None line = prev_line while True: _line = fp.readline() if _line == "": - return None, None + return prev_line, None if TIMESTAMP_REGEX.match(_line) is not None: return line, _line - line += line + line += _line @classmethod def parse(cls, file: Path) -> Generator[LogRow, None, None]: """Parse logs and yield rows.""" - with file.open(mode="r") as fp: + with file.open(mode="r", encoding="utf-8") as fp: prev_line: Optional[str] = fp.readline() current_period = 0 current_round = "agent_startup" current_behaviour = "agent_startup" while True: - line, prev_line = cls.get_next_log_block( - fp=fp, prev_line=cast(str, prev_line) - ) + line, prev_line = cls.get_next_log_block(fp=fp, prev_line=prev_line) if line is None and prev_line is None: break match = LOG_ROW_REGEX.match(string=cast(str, line)) - _timestamp, log_level, _, log_block = cast(re.Match, match).groups() + _timestamp, log_level, _, log_block, _ = cast(re.Match, match).groups() timestamp = datetime.strptime(_timestamp, TIME_FORMAT) - match = ENTER_BEHAVIOUR_REGEX.match(string=log_block) if match is not None: (current_behaviour,) = match.groups() diff --git a/autonomy/analyse/service.py b/autonomy/analyse/service.py index 6e8618b297..dcf6064f7d 100644 --- a/autonomy/analyse/service.py +++ b/autonomy/analyse/service.py @@ -22,8 +22,9 @@ import copy import logging +import os import re -from typing import Dict, List, Optional, OrderedDict, Set, cast +from typing import Any, Dict, List, Optional, OrderedDict, Set, Union, cast from aea.configurations.base import AgentConfig, SkillConfig from aea.configurations.data_types import ( @@ -34,8 +35,9 @@ ) from aea.crypto.base import LedgerApi from aea.helpers.cid import to_v0 +from aea.helpers.env_vars import apply_env_variables from aea.helpers.logging import setup_logger -from jsonschema.exceptions import ValidationError +from jsonschema.exceptions import ValidationError as SchemaValidationError from jsonschema.validators import Draft4Validator from requests.exceptions import ConnectionError as RequestConnectionError @@ -146,7 +148,6 @@ "required": [ "genesis_config", "service_id", - "tendermint_url", "max_healthcheck", "round_timeout_seconds", "sleep_time", @@ -155,7 +156,9 @@ "keeper_timeout", "reset_pause_duration", "drand_public_key", + "tendermint_url", "tendermint_com_url", + "tendermint_p2p_url", "tendermint_max_retries", "tendermint_check_sleep_delay", "reset_tendermint_after", @@ -168,19 +171,110 @@ "service_registry_address", "on_chain_service_id", "share_tm_config_on_startup", - "tendermint_p2p_url", + "use_termination", + "use_slashing", + "slash_cooldown_hours", + "slash_threshold_amount", + "light_slash_unit_amount", + "serious_slash_unit_amount", "setup", ], } ABCI = "abci" LEDGER = "ledger" +TERMINATION_ABCI = PublicId(author="valory", name="termination_abci", version="any") +SLASHING_ABCI = PublicId(author="valory", name="slashing_abci", version="any") +ENV_VAR_RE = re.compile( + r"^\$\{(?P[A-Z_0-9]+)?:?(?Pbool|int|float|str|list|dict)?:?(?P.+)?\}$" +) +REQUIRED_PROPERTY_RE = re.compile(r"'(.*)' is a required property") +PROPERTY_NOT_ALLOWED_RE = re.compile( + r"Additional properties are not allowed \((('(.*)'(,)? )+)(was|were) unexpected\)" +) + + +class CustomSchemaValidationError(SchemaValidationError): + """Custom schema validation error to report all errors at once.""" + + def __init__( + self, + extra_properties: Optional[List[str]] = None, + missing_properties: Optional[List[str]] = None, + not_having_enough_properties: Optional[List[str]] = None, + **kwargs: Any, + ) -> None: + """Initialize object.""" + self.extra_properties = extra_properties or [] + self.missing_properties = missing_properties or [] + self.not_having_enough_properties = not_having_enough_properties or [] + self.should_raise = False + error_strings = [] + if len(self.extra_properties) > 0: + self.should_raise = True + self.extra_properties_error = "Additional properties found " + ", ".join( + map(lambda x: f"'{x}'", self.extra_properties) + ) + error_strings.append(self.extra_properties_error) + + if len(self.missing_properties) > 0: + self.should_raise = True + self.missing_properties_error = ( + "Following properties are require but missing " + + ", ".join(map(lambda x: f"'{x}'", self.missing_properties)) + ) + error_strings.append(self.missing_properties_error) + + if len(self.not_having_enough_properties) > 0: + self.should_raise = True + self.not_having_enough_properties_error = ";".join( + self.not_having_enough_properties + ) + error_strings.append(self.not_having_enough_properties_error) + + message = ";".join(error_strings) + super().__init__(message, **kwargs) + + +class CustomSchemaValidator(Draft4Validator): + """Custom schema validator to report all missing fields at once.""" + + def validate(self, *args: Any, **kwargs: Any) -> None: + """Validate and raise all errors at once.""" + missing = [] + extra = [] + not_enough_properties = [] + for error in self.iter_errors(*args, **kwargs): + message = cast(SchemaValidationError, error).message + missing_property_check = REQUIRED_PROPERTY_RE.match(message) + if missing_property_check is not None: + (missing_property,) = cast(re.Match, missing_property_check).groups() + missing.append(missing_property) + continue + + property_not_allowed_check = PROPERTY_NOT_ALLOWED_RE.match(message) + if property_not_allowed_check is not None: + extra += re.findall( + "[a-zA-Z0-9]+", property_not_allowed_check.groups()[0] + ) + continue + + if "does not have enough properties" in message: + not_enough_properties.append(message) + + error = CustomSchemaValidationError( + extra_properties=extra, + missing_properties=missing, + not_having_enough_properties=not_enough_properties, + ) + if error.should_raise: + raise error + -UNKNOWN_LEDGER_RE = re.compile(r".*\(\'(.*)\' was unexpected\)") -ABCI_CONNECTION_VALIDATOR = Draft4Validator(schema=ABCI_CONNECTION_SCHEMA) -LEDGER_CONNECTION_VALIDATOR = Draft4Validator(schema=LEDGER_CONNECTION_SCHEMA) -ABCI_SKILL_VALIDATOR = Draft4Validator(schema=ABCI_SKILL_SCHEMA) -ABCI_SKILL_MODEL_PARAMS_VALIDATOR = Draft4Validator( +ABCI_CONNECTION_VALIDATOR = CustomSchemaValidator(schema=ABCI_CONNECTION_SCHEMA) +LEDGER_CONNECTION_VALIDATOR = CustomSchemaValidator(schema=LEDGER_CONNECTION_SCHEMA) +ABCI_SKILL_VALIDATOR = CustomSchemaValidator(schema=ABCI_SKILL_SCHEMA) +ABCI_SKILL_MODEL_PARAMS_VALIDATOR = CustomSchemaValidator( schema=ABCI_SKILL_MODEL_PARAMS_SCHEMA ) @@ -195,14 +289,24 @@ class ServiceAnalyser: def __init__( self, service_config: Service, + abci_skill_id: PublicId, is_on_chain_check: bool = False, logger: Optional[logging.Logger] = None, + skip_warnings: bool = False, ) -> None: """Initialise object.""" self.service_config = service_config + self.abci_skill_id = abci_skill_id self.is_on_chain_check = is_on_chain_check - self.logger = logger or setup_logger(name="ServiceAnalyser") + self.logger = logger or setup_logger(name="autonomy.analyse") + self.skip_warning = skip_warnings + + def _warn(self, msg: str) -> None: + """Raise warning.""" + if self.skip_warning: # pragma: nocover + return + self.logger.warning(msg=msg) def check_on_chain_state( self, @@ -226,7 +330,7 @@ def check_on_chain_state( service_state = ServiceState(_service_state) if service_state != ServiceState.DEPLOYED: - self.logger.warning( + self._warn( f"Service needs to be in deployed state on-chain; Current state={service_state}" ) @@ -273,7 +377,6 @@ def _check_overrides_recursively( # service has them and agent does not - warning check_from_set, check_with_set = set(check_from), set(check_with) - missing = check_with_set - check_from_set if len(missing) > 0: message = ( @@ -281,7 +384,7 @@ def _check_overrides_recursively( f"\tPath: {path_str}\n" f"\tMissing parameters: {missing}\n" ) - self.logger.warning(message) + self._warn(message) missing = check_from_set - check_with_set if len(missing) > 0: @@ -290,7 +393,7 @@ def _check_overrides_recursively( f"\tPath: {path_str}\n" f"\tMissing parameters: {missing}\n" ) - self.logger.warning(message) + self._warn(message) for key in check_with_set.intersection(check_from_set): if not isinstance(check_from[key], (dict, Dict, OrderedDict)): @@ -304,8 +407,10 @@ def _check_overrides_recursively( path=[*path, key], ) - def cross_verify_overrides( - self, agent_config: AgentConfig, skill_config: SkillConfig + def cross_verify_overrides( # pylint: disable=too-many-locals + self, + agent_config: AgentConfig, + skill_config: SkillConfig, ) -> None: """Cross verify overrides between service config and agent config""" @@ -319,24 +424,52 @@ def cross_verify_overrides( for component_override in self.service_config.overrides } + # Skip abci connection since it's not required to be manually overridden + missing_from_service = [ + cid + for cid in agent_overrides - service_overrides + if cid.public_id.name != ABCI + and cid.component_type != ComponentType.CONNECTION + ] + if len(missing_from_service) > 0: + self._warn( + "\n\t- ".join( + map( + str, + [ + "Overrides with following component IDs are defined in the agent configuration but not in the service configuration", + *missing_from_service, + ], + ) + ) + ) + missing_from_agent = service_overrides - agent_overrides if len(missing_from_agent) > 0: raise ServiceValidationFailed( - "Service config has an overrides which are not defined in the agent config; " - f"packages with missing overrides={missing_from_agent}" + "\n\t- ".join( + map( + str, + [ + "Overrides with following component IDs are defined in the service configuration but not in the agent configuration", + *missing_from_agent, + ], + ) + ) ) - skill_override_from_agent = agent_config.component_configurations[ - skill_config.package_id - ] - skill_config_to_check = { - "models": { - "params": {"args": skill_config.json["models"]["params"]["args"]}, - } + skill_override_from_agent = apply_env_variables( + agent_config.component_configurations[skill_config.package_id], + env_variables=os.environ.copy(), + ) + skill_config_to_check: Dict[str, Dict] = {"models": {}} + skill_config_json = copy.deepcopy(skill_config.json) + skill_config_to_check["models"]["params"] = { + "args": skill_config_json["models"]["params"]["args"] } - if "benchmark_tool" in skill_config.json["models"]: + if "benchmark_tool" in skill_config_json["models"]: skill_config_to_check["models"]["benchmark_tool"] = { - "args": skill_config.json["models"]["benchmark_tool"]["args"] + "args": skill_config_json["models"]["benchmark_tool"]["args"] } for override in self.service_config.overrides: @@ -366,6 +499,7 @@ def cross_verify_overrides( check_from_name=str(self.service_config.package_id), check_with_name=str(agent_config.package_id), ) + break self.logger.info("Cross verifying overrides between skill and agent") self._check_overrides_recursively( @@ -375,112 +509,315 @@ def cross_verify_overrides( check_with_name=str(skill_config.package_id), ) + @classmethod + def validate_override_env_vars( + cls, + overrides: Union[OrderedDict, dict], + validate_env_var_name: bool = False, + json_path: Optional[List[str]] = None, + ) -> List[str]: + """Validate environment variables.""" + errors = [] + json_path = json_path or [] + for key, value in overrides.items(): + if key in ( + "target_skill_id", + "identifier", + "ledger_id", + "message_format", + "not_after", + "not_before", + "save_path", + "is_abstract", + ): + continue # pragma: nocover + _json_path = [*json_path, str(key)] + if isinstance(value, (dict, OrderedDict)): + errors += cls.validate_override_env_vars( + value, + validate_env_var_name=validate_env_var_name, + json_path=_json_path, + ) + elif isinstance(value, list): + for i, obj in enumerate(value): + if not isinstance(obj, (dict, OrderedDict)): + continue # pragma: nocover + errors += cls.validate_override_env_vars( + obj, + validate_env_var_name=validate_env_var_name, + json_path=[*_json_path, str(i)], + ) + else: + json_path_str = ".".join(_json_path) + try: + re_result = ENV_VAR_RE.match(value) + if re_result is None: + errors.append( + f"`{json_path_str}` needs environment variable defined in following format " + "${ENV_VAR_NAME:DATA_TYPE:DEFAULT_VALUE}" + ) + continue + + result = re_result.groupdict() + if validate_env_var_name and result.get("name") is None: + errors.append( + f"Enviroment variable template for `{json_path_str}` does not have variable name defined" + ) + + if result.get("type") is None: + errors.append( + f"Enviroment variable template for `{json_path_str}` does not have type defined" + ) + continue + + if result.get("value") is None: + errors.append( + f"Enviroment variable template for `{json_path_str}` does not have default value defined" + ) + continue + + apply_env_variables( + data={key: value}, env_variables=os.environ.copy() + ) + except TypeError: + errors.append( + f"`{json_path_str}` needs to be defined as a environment variable" + ) + except (ValueError, KeyError) as e: + errors.append( + f"`{json_path_str}` validation failed with following error; {e}" + ) + + return errors + + def validate_agent_override_env_vars(self, agent_config: AgentConfig) -> None: + """Check if all of the overrides are defined as a env vars in the agent config""" + + self.logger.info( + f"Validating agent {agent_config.public_id} overrides for environment variable definitions" + ) + for package_id, override in agent_config.component_configurations.items(): + errors = self.validate_override_env_vars(overrides=override) + if len(errors) > 0: + raise ServiceValidationFailed( + "\n\t- ".join( + [ + f"{package_id} envrionment variable validation failed with following error", + *errors, + ] + ), + ) + + def validate_service_override_env_vars(self) -> None: + """Check if all of the overrides are defined as a env vars in the agent config""" + self.logger.info( + f"Validating service {self.service_config.public_id} overrides for environment variable definitions" + ) + errors = [] + for _component_config in self.service_config.overrides: + ( + component_config, + component_id, + _, + ) = Service.process_metadata(configuration=_component_config.copy()) + errors = self.validate_override_env_vars( + overrides=component_config, validate_env_var_name=True + ) + if len(errors) > 0: + raise ServiceValidationFailed( + "\n\t- ".join( + [ + f"{component_id} envrionment variable validation failed with following error", + *errors, + ] + ), + ) + @staticmethod def _validate_override( validator: Draft4Validator, overrides: Dict, has_multiple_overrides: bool, error_message: str, + raise_custom_exception: bool = True, ) -> None: """Run validator on the given override.""" - try: - if has_multiple_overrides: - _ = list(map(validator.validate, overrides.values())) - else: + + def _validate_override( + validator: Draft4Validator, + overrides: Dict, + error_message: str, + ) -> None: + try: validator.validate(overrides) - except ValidationError as e: - raise ServiceValidationFailed(error_message.format(error=e.message)) from e + except CustomSchemaValidationError as e: + if raise_custom_exception: + raise ServiceValidationFailed( + error_message.format(error=e.message) + ) from e + raise + + if has_multiple_overrides: + for idx, override in overrides.items(): + _validate_override( + validator=validator, + overrides=override, + error_message=f"{error_message} at override index {idx}", + ) + else: + _validate_override( + validator=validator, + overrides=overrides, + error_message=error_message, + ) - @classmethod def validate_override( - cls, + self, component_id: ComponentId, override: Dict, has_multiple_overrides: bool, ) -> None: """Validate override""" - if ( - component_id.component_type == ComponentType.SKILL - and ABCI in component_id.name - ): - cls._validate_override( + if component_id.public_id == self.abci_skill_id: + self._validate_override( validator=ABCI_SKILL_VALIDATOR, overrides=override, has_multiple_overrides=has_multiple_overrides, - error_message="ABCI skill validation failed; {error}", + error_message=( + "ABCI Skill `" + + str(component_id.public_id) + + "` override validation failed; {error}" + ), ) + if ( component_id.component_type == ComponentType.CONNECTION and component_id.name == ABCI ): - cls._validate_override( + self._validate_override( validator=ABCI_CONNECTION_VALIDATOR, overrides=override, has_multiple_overrides=has_multiple_overrides, error_message="ABCI connection validation failed; {error}", ) + if ( component_id.component_type == ComponentType.CONNECTION and component_id.name == LEDGER ): try: - cls._validate_override( + self._validate_override( validator=LEDGER_CONNECTION_VALIDATOR, overrides=override, has_multiple_overrides=has_multiple_overrides, - error_message="Ledger connection validation failed; {error}", - ) - except ServiceValidationFailed as e: - (msg, *_) = e.args - unknown_ledger_match = UNKNOWN_LEDGER_RE.match(msg) - if unknown_ledger_match is None: - raise - - (unknown_ledger,) = cast(re.Match, unknown_ledger_match).groups() - logging.warning( - f"Unknown ledger configuration found with name `{unknown_ledger}`" + error_message="{error}", + raise_custom_exception=False, ) + except CustomSchemaValidationError as e: + if len(e.not_having_enough_properties) > 0: + raise ServiceValidationFailed( + f"{component_id} override needs at least one ledger API definition" + ) from e + + if len(e.missing_properties) > 0: + raise ServiceValidationFailed( + f"Ledger connection validation failed; {e.missing_properties_error}" + ) from e + + if len(e.extra_properties) > 0: + self._warn( + "\n\t- ".join( + [ + f"Following unknown ledgers found in the {component_id} override", + *e.extra_properties, + ] + ) + ) + + def _check_for_dependency( + self, dependencies: Set[PublicId], dependency: PublicId + ) -> None: + """Check termination ABCI skill is an dependency for the agent""" + for _dependency in dependencies: + if _dependency.to_any() == dependency: + return + self.logger.warning(f"{dependency} is not defined as a dependency") def validate_skill_config(self, skill_config: SkillConfig) -> None: """Check required overrides.""" - self.logger.info("Validating skill overrides") + self.logger.info(f"Validating ABCI skill {skill_config.public_id}") model_params = skill_config.models.read("params") + if model_params is None: + raise ServiceValidationFailed( + f"The chained ABCI skill `{skill_config.public_id}` does not contain `params` model" + ) + self._validate_override( validator=ABCI_SKILL_MODEL_PARAMS_VALIDATOR, overrides=model_params.args, has_multiple_overrides=False, - error_message="ABCI skill model parameter validation failed; {error}", + error_message="ABCI skill validation failed; {error}", ) + self._check_for_dependency(skill_config.skills, TERMINATION_ABCI) + self._check_for_dependency(skill_config.skills, SLASHING_ABCI) + self.logger.info("No issues found in the ABCI skill configuration") def validate_agent_overrides(self, agent_config: AgentConfig) -> None: """Check required overrides.""" - self.logger.info("Validating agent overrides") + self.logger.info(f"Validating agent {agent_config.public_id} overrides") + errors = [] for ( component_id, component_config, ) in agent_config.component_configurations.items(): - self.validate_override( - component_id=component_id, - override=component_config, - has_multiple_overrides=False, + try: + self.validate_override( + component_id=component_id, + override=component_config, + has_multiple_overrides=False, + ) + except ServiceValidationFailed as e: + errors.append(str(e)) + + if len(errors) > 0: + error_string = "\n\t- ".join(errors) + raise ServiceValidationFailed( + "Agent overrides validation failed with following errors" + f"\n\t- {error_string}" ) + self._check_for_dependency(agent_config.skills, TERMINATION_ABCI) + self._check_for_dependency(agent_config.skills, SLASHING_ABCI) + self.logger.info("No issues found in the agent overrides") + def validate_service_overrides(self) -> None: """Check required overrides.""" self.logger.info("Validating service overrides") + errors = [] for _component_config in self.service_config.overrides: ( component_config, component_id, has_multiple_overrides, ) = Service.process_metadata(configuration=_component_config.copy()) - self.logger.info(f"Validating {component_id} from the service overrides") - self.validate_override( - component_id=component_id, - override=component_config, - has_multiple_overrides=has_multiple_overrides, + try: + self.validate_override( + component_id=component_id, + override=component_config, + has_multiple_overrides=has_multiple_overrides, + ) + except ServiceValidationFailed as e: + errors.append(str(e)) + + if len(errors) > 0: + error_string = "\n\t- ".join(errors) + raise ServiceValidationFailed( + "Service overrides validation failed with following errors" + f"\n\t- {error_string}" ) + + self.logger.info("No issues found in the service overrides") diff --git a/autonomy/chain/base.py b/autonomy/chain/base.py index 56fc299e89..dda1437412 100644 --- a/autonomy/chain/base.py +++ b/autonomy/chain/base.py @@ -20,7 +20,7 @@ """Chain interaction base classes.""" from enum import Enum -from typing import Optional +from typing import Dict, Optional from aea.configurations.data_types import PublicId from aea.contracts.base import Contract @@ -30,12 +30,20 @@ COMPONENT_REGISTRY_CONTRACT, CONTRACTS_DIR_FRAMEWORK, CONTRACTS_DIR_LOCAL, + ERC20_CONTRACT, + GNOSIS_SAFE_CONTRACT, + GNOSIS_SAFE_PROXY_FACTORY_CONTRACT, + MULTISEND_CONTRACT, REGISTRIES_MANAGER_CONTRACT, SERVICE_MANAGER_CONTRACT, SERVICE_REGISTRY_CONTRACT, + SERVICE_REGISTRY_TOKEN_UTILITY_CONTRACT, ) +_contract_registry_cache: Dict[PublicId, Contract] = {} + + class UnitType(Enum): """ Unit type @@ -62,23 +70,34 @@ class ServiceState(Enum): TERMINATED_BONDED = 5 -class RegistryContracts: +class RegistryContracts: # pylint: disable=too-many-instance-attributes """On chain registry contracts helper""" + _erc20: Optional[Contract] = None _registries_manager: Optional[Contract] = None _service_manager: Optional[Contract] = None _component_registry: Optional[Contract] = None _agent_registry: Optional[Contract] = None _service_registry: Optional[Contract] = None + _service_registry_token_utility: Optional[Contract] = None + _gnosis_safe: Optional[Contract] = None + _gnosis_safe_proxy_factory: Optional[Contract] = None + _multisend: Optional[Contract] = None @staticmethod - def get_contract(public_id: PublicId) -> Contract: + def get_contract(public_id: PublicId, cache: bool = True) -> Contract: """Load contract for given public id.""" + if cache and public_id.name in _contract_registry_cache: + return _contract_registry_cache[public_id.name] + # check if a local package is available contract_dir = CONTRACTS_DIR_LOCAL / public_id.name if contract_dir.exists(): - return Contract.from_dir(directory=contract_dir) + _contract_registry_cache[public_id.name] = Contract.from_dir( + directory=contract_dir + ) + return _contract_registry_cache[public_id.name] # if local package is not available use one from the data directory contract_dir = CONTRACTS_DIR_FRAMEWORK / public_id.name @@ -87,7 +106,10 @@ def get_contract(public_id: PublicId) -> Contract: f"Contract package {public_id} not found in the open-autonomy installation, " "please reinstall the package" ) - return Contract.from_dir(directory=contract_dir) + _contract_registry_cache[public_id.name] = Contract.from_dir( + directory=contract_dir + ) + return _contract_registry_cache[public_id.name] @property def registries_manager( @@ -149,5 +171,66 @@ def service_registry( return self._service_registry + @property + def service_registry_token_utility( + self, + ) -> Contract: + """Returns an instance of the service registry token utility contract.""" + if self._service_registry_token_utility is None: + self._service_registry_token_utility = self.get_contract( + public_id=SERVICE_REGISTRY_TOKEN_UTILITY_CONTRACT, + ) + + return self._service_registry_token_utility + + @property + def erc20( + self, + ) -> Contract: + """Returns an instance of the service registry token utility contract.""" + if self._erc20 is None: + self._erc20 = self.get_contract( + public_id=ERC20_CONTRACT, + ) + + return self._erc20 + + @property + def gnosis_safe( + self, + ) -> Contract: + """Returns an instance of the service registry token utility contract.""" + if self._gnosis_safe is None: + _ = self.gnosis_safe_proxy_factory + self._gnosis_safe = self.get_contract( + public_id=GNOSIS_SAFE_CONTRACT, + ) + + return self._gnosis_safe + + @property + def gnosis_safe_proxy_factory( + self, + ) -> Contract: + """Returns an instance of the service registry token utility contract.""" + if self._gnosis_safe_proxy_factory is None: + self._gnosis_safe_proxy_factory = self.get_contract( + public_id=GNOSIS_SAFE_PROXY_FACTORY_CONTRACT, + ) + + return self._gnosis_safe_proxy_factory + + @property + def multisend( + self, + ) -> Contract: + """Returns an instance of the service registry token utility contract.""" + if self._multisend is None: + self._multisend = self.get_contract( + public_id=MULTISEND_CONTRACT, + ) + + return self._multisend + registry_contracts = RegistryContracts() diff --git a/autonomy/chain/config.py b/autonomy/chain/config.py index 31f563d2ac..8e013d8cde 100644 --- a/autonomy/chain/config.py +++ b/autonomy/chain/config.py @@ -24,7 +24,12 @@ from enum import Enum from typing import Dict, Optional, cast -from autonomy.chain import constants as chain_constants +from autonomy.chain.constants import ( + CustomAddresses, + EthereumAddresses, + GoerliAddresses, + HardhatAddresses, +) DEFAULT_LOCAL_RPC = "http://127.0.0.1:8545" @@ -39,7 +44,6 @@ def _get_chain_id_for_custom_chain() -> Optional[int]: chain_id = os.environ.get("CUSTOM_CHAIN_ID") if chain_id is None: return None - return int(chain_id) @@ -52,6 +56,14 @@ class ChainType(Enum): ETHEREUM = "ethereum" +ADDRESS_CONTAINERS = { + ChainType.LOCAL: HardhatAddresses, + ChainType.CUSTOM: CustomAddresses, + ChainType.GOERLI: GoerliAddresses, + ChainType.ETHEREUM: EthereumAddresses, +} + + @dataclass class ContractConfig: """Contract config class.""" @@ -121,65 +133,81 @@ class ContractConfigs: # pylint: disable=too-few-public-methods component_registry = ContractConfig( name="component_registry", contracts={ - chain_type: getattr( - chain_constants, f"COMPONENT_REGISTRY_ADDRESS_{chain_type.name}" - ) - for chain_type in ChainType + chain_type: container.get("component_registry") + for chain_type, container in ADDRESS_CONTAINERS.items() }, ) agent_registry = ContractConfig( name="agent_registry", contracts={ - chain_type: getattr( - chain_constants, f"AGENT_REGISTRY_ADDRESS_{chain_type.name}" - ) - for chain_type in ChainType + chain_type: container.get("agent_registry") + for chain_type, container in ADDRESS_CONTAINERS.items() }, ) service_registry = ContractConfig( name="service_registry", contracts={ - chain_type: getattr( - chain_constants, f"SERVICE_REGISTRY_ADDRESS_{chain_type.name}" - ) - for chain_type in ChainType + chain_type: container.get("service_registry") + for chain_type, container in ADDRESS_CONTAINERS.items() }, ) service_manager = ContractConfig( name="service_manager", contracts={ - chain_type: getattr( - chain_constants, f"SERVICE_MANAGER_ADDRESS_{chain_type.name}" - ) - for chain_type in ChainType + chain_type: container.get("service_manager") + for chain_type, container in ADDRESS_CONTAINERS.items() }, ) registries_manager = ContractConfig( name="registries_manager", contracts={ - chain_type: getattr( - chain_constants, f"REGISTRIES_MANAGER_ADDRESS_{chain_type.name}" - ) - for chain_type in ChainType + chain_type: container.get("registries_manager") + for chain_type, container in ADDRESS_CONTAINERS.items() }, ) gnosis_safe_proxy_factory = ContractConfig( name="gnosis_safe_proxy_factory", contracts={ - chain_type: getattr( - chain_constants, f"GNOSIS_SAFE_MULTISIG_ADDRESS_{chain_type.name}" - ) - for chain_type in ChainType + chain_type: container.get("gnosis_safe_proxy_factory") + for chain_type, container in ADDRESS_CONTAINERS.items() + }, + ) + + gnosis_safe_same_address_multisig = ContractConfig( + name="gnosis_safe_same_address_multisig", + contracts={ + chain_type: container.get("gnosis_safe_same_address_multisig") + for chain_type, container in ADDRESS_CONTAINERS.items() + }, + ) + + service_registry_token_utility = ContractConfig( + name="service_registry_token_utility", + contracts={ + chain_type: container.get("service_registry_token_utility") + for chain_type, container in ADDRESS_CONTAINERS.items() }, ) + multisend = ContractConfig( + name="multisend", + contracts={ + chain_type: container.get("multisend") + for chain_type, container in ADDRESS_CONTAINERS.items() + }, + ) + + erc20 = ContractConfig( + name="erc20", + contracts={}, + ) + @classmethod def get(cls, name: str) -> ContractConfig: """Return chain config for given chain type.""" - return cast(ContractConfig, getattr(cls, name)) diff --git a/autonomy/chain/constants.py b/autonomy/chain/constants.py index 18651641bf..a96b2923b9 100644 --- a/autonomy/chain/constants.py +++ b/autonomy/chain/constants.py @@ -20,6 +20,8 @@ """Chain constants""" import os +from dataclasses import dataclass +from typing import cast from aea.configurations.constants import CONTRACTS, PACKAGES from aea.configurations.data_types import PublicId @@ -29,53 +31,116 @@ from autonomy.data import DATA_DIR -EVENT_VERIFICATION_TIMEOUT = 60.0 - CONTRACTS_DIR_FRAMEWORK = DATA_DIR / CONTRACTS CONTRACTS_DIR_LOCAL = ( AUTONOMY_DIR.parent / PACKAGES / VALORY / CONTRACTS ) # use from an editable/local installation +ERC20_TOKEN_ADDRESS_LOCAL = "0x1291Be112d480055DaFd8a610b7d1e203891C274" # nosec + + +@dataclass +class ContractAddresses: # pylint: disable=too-many-instance-attributes + """Contract addresses container for a chain.""" + + component_registry: str + agent_registry: str + registries_manager: str + service_registry: str + service_registry_token_utility: str + service_manager: str + gnosis_safe_proxy_factory: str + gnosis_safe_same_address_multisig: str + multisend: str + + def get(self, name: str) -> str: + """Returns the contract address.""" + return cast(str, getattr(self, name)) + + +HardhatAddresses = ContractAddresses( # nosec + component_registry="0x5FbDB2315678afecb367f032d93F642f64180aa3", + agent_registry="0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512", + registries_manager="0x9fE46736679d2D9a65F0992F2272dE9f3c7fa6e0", + service_registry="0x998abeb3E57409262aE5b751f60747921B33613E", + service_manager="0x4c5859f0F772848b2D91F1D83E2Fe57935348029", + gnosis_safe_proxy_factory="0x0E801D84Fa97b50751Dbf25036d067dCf18858bF", + gnosis_safe_same_address_multisig="0x8f86403A4DE0BB5791fa46B8e795C547942fE4Cf", + service_registry_token_utility="0x36C02dA8a0983159322a80FFE9F24b1acfF8B570", + multisend="0x9d4454B023096f34B160D6B654540c56A1F81688", +) + +EthereumAddresses = ContractAddresses( # nosec + component_registry="0x15bd56669F57192a97dF41A2aa8f4403e9491776", + agent_registry="0x2F1f7D38e4772884b88f3eCd8B6b9faCdC319112", + registries_manager="0x9eC9156dEF5C613B2a7D4c46C383F9B58DfcD6fE", + service_registry="0x48b6af7B12C71f09e2fC8aF4855De4Ff54e775cA", + service_registry_token_utility="0x3Fb926116D454b95c669B6Bf2E7c3bad8d19affA", + service_manager="0x2EA682121f815FBcF86EA3F3CaFdd5d67F2dB143", + gnosis_safe_proxy_factory="0x46C0D07F55d4F9B5Eed2Fc9680B5953e5fd7b461", + gnosis_safe_same_address_multisig="0xfa517d01DaA100cB1932FA4345F68874f7E7eF46", + multisend="0x40A2aCCbd92BCA938b02010E17A5b8929b49130D", +) + +GoerliAddresses = ContractAddresses( # nosec + component_registry="0x7Fd1F4b764fA41d19fe3f63C85d12bf64d2bbf68", + agent_registry="0xEB5638eefE289691EcE01943f768EDBF96258a80", + registries_manager="0x10c5525F77F13b28f42c5626240c001c2D57CAd4", + service_registry="0x1cEe30D08943EB58EFF84DD1AB44a6ee6FEff63a", + service_registry_token_utility="0x6d9b08701Af43D68D991c074A27E4d90Af7f2276", + service_manager="0x1d333b46dB6e8FFd271b6C2D2B254868BD9A2dbd", + gnosis_safe_proxy_factory="0x65dD51b02049ad1B6FF7fa9Ea3322E1D2CAb1176", + gnosis_safe_same_address_multisig="0x06467Cb835da623384a22aa902647784C1c9f5Ae", + multisend="0x40A2aCCbd92BCA938b02010E17A5b8929b49130D", +) -# contract addresses from `valory/autonolas-registries` image -COMPONENT_REGISTRY_ADDRESS_LOCAL = "0x5FbDB2315678afecb367f032d93F642f64180aa3" -AGENT_REGISTRY_ADDRESS_LOCAL = "0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512" -REGISTRIES_MANAGER_ADDRESS_LOCAL = "0x9fE46736679d2D9a65F0992F2272dE9f3c7fa6e0" -SERVICE_MANAGER_ADDRESS_LOCAL = "0x70e0bA845a1A0F2DA3359C97E0285013525FFC49" -SERVICE_REGISTRY_ADDRESS_LOCAL = "0x998abeb3E57409262aE5b751f60747921B33613E" -GNOSIS_SAFE_MULTISIG_ADDRESS_LOCAL = "0x0E801D84Fa97b50751Dbf25036d067dCf18858bF" - - -# contract addresses from `https://github.com/valory-xyz/autonolas-registries/blob/main/docs/mainnet_addresses.json` file -COMPONENT_REGISTRY_ADDRESS_ETHEREUM = "0x15bd56669F57192a97dF41A2aa8f4403e9491776" -AGENT_REGISTRY_ADDRESS_ETHEREUM = "0x2F1f7D38e4772884b88f3eCd8B6b9faCdC319112" -REGISTRIES_MANAGER_ADDRESS_ETHEREUM = "0x9eC9156dEF5C613B2a7D4c46C383F9B58DfcD6fE" -SERVICE_MANAGER_ADDRESS_ETHEREUM = "0x38b062d11CD7596Ab5aDFe4d0e9F0dC3218E5389" -SERVICE_REGISTRY_ADDRESS_ETHEREUM = "0x48b6af7B12C71f09e2fC8aF4855De4Ff54e775cA" -GNOSIS_SAFE_MULTISIG_ADDRESS_ETHEREUM = "0x1c2cD884127b080F940b7546c1e9aaf525b1FA55" - -# contract addresses from `https://raw.githubusercontent.com/valory-xyz/autonolas-registries/main/scripts/deployment/globals_goerli.json` -COMPONENT_REGISTRY_ADDRESS_GOERLI = "0x7Fd1F4b764fA41d19fe3f63C85d12bf64d2bbf68" -AGENT_REGISTRY_ADDRESS_GOERLI = "0xEB5638eefE289691EcE01943f768EDBF96258a80" -REGISTRIES_MANAGER_ADDRESS_GOERLI = "0x10c5525F77F13b28f42c5626240c001c2D57CAd4" -SERVICE_MANAGER_ADDRESS_GOERLI = "0xcDdD9D9ABaB36fFa882530D69c73FeE5D4001C2d" -SERVICE_REGISTRY_ADDRESS_GOERLI = "0x1cEe30D08943EB58EFF84DD1AB44a6ee6FEff63a" -GNOSIS_SAFE_MULTISIG_ADDRESS_GOERLI = "0x65dD51b02049ad1B6FF7fa9Ea3322E1D2CAb1176" - -# contract addressed for a custom chain -COMPONENT_REGISTRY_ADDRESS_CUSTOM = os.environ.get("CUSTOM_COMPONENT_REGISTRY_ADDRESS") -AGENT_REGISTRY_ADDRESS_CUSTOM = os.environ.get("CUSTOM_AGENT_REGISTRY_ADDRESS") -REGISTRIES_MANAGER_ADDRESS_CUSTOM = os.environ.get("CUSTOM_REGISTRIES_MANAGER_ADDRESS") -SERVICE_MANAGER_ADDRESS_CUSTOM = os.environ.get("CUSTOM_SERVICE_MANAGER_ADDRESS") -SERVICE_REGISTRY_ADDRESS_CUSTOM = os.environ.get("CUSTOM_SERVICE_REGISTRY_ADDRESS") -GNOSIS_SAFE_MULTISIG_ADDRESS_CUSTOM = os.environ.get( - "CUSTOM_GNOSIS_SAFE_MULTISIG_ADDRESS" +CustomAddresses = ContractAddresses( + component_registry=cast(str, os.environ.get("CUSTOM_COMPONENT_REGISTRY_ADDRESS")), + agent_registry=cast(str, os.environ.get("CUSTOM_AGENT_REGISTRY_ADDRESS")), + registries_manager=cast(str, os.environ.get("CUSTOM_REGISTRIES_MANAGER_ADDRESS")), + service_manager=cast(str, os.environ.get("CUSTOM_SERVICE_MANAGER_ADDRESS")), + service_registry=cast(str, os.environ.get("CUSTOM_SERVICE_REGISTRY_ADDRESS")), + gnosis_safe_proxy_factory=cast( + str, os.environ.get("CUSTOM_GNOSIS_SAFE_PROXY_FACTORY_ADDRESS") + ), + gnosis_safe_same_address_multisig=cast( + str, os.environ.get("CUSTOM_GNOSIS_SAFE_SAME_ADDRESS_MULTISIG_ADDRESS") + ), + service_registry_token_utility=cast( + str, os.environ.get("CUSTOM_SERVICE_REGISTRY_TOKEN_UTILITY_ADDRESS") + ), + multisend=cast( + str, + os.environ.get( + "CUSTOM_MULTISEND_ADDRESS", "0x40A2aCCbd92BCA938b02010E17A5b8929b49130D" + ), + ), ) + # Contract PublicIds COMPONENT_REGISTRY_CONTRACT = PublicId.from_str("valory/component_registry") AGENT_REGISTRY_CONTRACT = PublicId.from_str("valory/agent_registry") REGISTRIES_MANAGER_CONTRACT = PublicId.from_str("valory/registries_manager") SERVICE_MANAGER_CONTRACT = PublicId.from_str("valory/service_manager") SERVICE_REGISTRY_CONTRACT = PublicId.from_str("valory/service_registry") -GNOSIS_SAFE_MULTISIG_CONTRACT = PublicId.from_str("valory/gnosis_safe_proxy_factory") +GNOSIS_SAFE_CONTRACT = PublicId.from_str("valory/gnosis_safe") +GNOSIS_SAFE_PROXY_FACTORY_CONTRACT = PublicId.from_str( + "valory/gnosis_safe_proxy_factory" +) +GNOSIS_SAFE_SAME_ADDRESS_MULTISIG_CONTRACT = PublicId.from_str( + "valory/gnosis_safe_same_address_multisig" +) +SERVICE_REGISTRY_TOKEN_UTILITY_CONTRACT = PublicId.from_str( + "valory/service_registry_token_utility" +) +MULTISEND_CONTRACT = PublicId.from_str("valory/multisend") +ERC20_CONTRACT = PublicId.from_str("valory/erc20") + +SERVICE_MANAGER_TOKEN_COMPATIBLE_CHAINS = ( + 1, + 5, + 31337, + 100, + 10200, +) diff --git a/autonomy/chain/exceptions.py b/autonomy/chain/exceptions.py index 834869770b..0391940209 100644 --- a/autonomy/chain/exceptions.py +++ b/autonomy/chain/exceptions.py @@ -24,12 +24,20 @@ class ChainInteractionError(Exception): """Base chain interaction failure.""" -class ComponentMintFailed(ChainInteractionError): - """Raise when component minting fails.""" +class RPCError(ChainInteractionError): + """RPC error.""" + + +class TxBuildError(ChainInteractionError): + """Tx build error.""" + + +class ChainTimeoutError(ChainInteractionError): + """Timeout error for interecting with chain.""" -class FailedToRetrieveTokenId(ChainInteractionError): - """Raise when token ID retrieving fails for minted component.""" +class ComponentMintFailed(ChainInteractionError): + """Raise when component minting fails.""" class FailedToRetrieveComponentMetadata(ChainInteractionError): @@ -54,3 +62,11 @@ class InstanceRegistrationFailed(ChainInteractionError): class ServiceDeployFailed(ChainInteractionError): """Raise when service activation fails.""" + + +class TerminateServiceFailed(ChainInteractionError): + """Raise when service termination fails.""" + + +class UnbondServiceFailed(ChainInteractionError): + """Raise when service unbond call fails.""" diff --git a/autonomy/chain/mint.py b/autonomy/chain/mint.py index 90c8d4a379..44d6375b99 100644 --- a/autonomy/chain/mint.py +++ b/autonomy/chain/mint.py @@ -19,41 +19,63 @@ """Helpers for minting components""" -import datetime import time +from datetime import datetime from math import ceil -from typing import Callable, Dict, List, Optional, Tuple +from typing import Callable, Dict, List, Optional, Tuple, cast +from aea.configurations.data_types import PublicId from aea.crypto.base import Crypto, LedgerApi -from requests.exceptions import ConnectionError as RequestsConnectionError from autonomy.chain.base import UnitType, registry_contracts from autonomy.chain.config import ChainType, ContractConfigs from autonomy.chain.constants import ( AGENT_REGISTRY_CONTRACT, COMPONENT_REGISTRY_CONTRACT, - EVENT_VERIFICATION_TIMEOUT, REGISTRIES_MANAGER_CONTRACT, SERVICE_MANAGER_CONTRACT, SERVICE_REGISTRY_CONTRACT, ) -from autonomy.chain.exceptions import ( - ComponentMintFailed, - FailedToRetrieveTokenId, - InvalidMintParameter, -) +from autonomy.chain.exceptions import ComponentMintFailed, InvalidMintParameter +from autonomy.chain.tx import TxSettler + + +try: + from web3.exceptions import Web3Exception +except (ModuleNotFoundError, ImportError): + Web3Exception = Exception DEFAULT_NFT_IMAGE_HASH = "bafybeiggnad44tftcrenycru2qtyqnripfzitv5yume4szbkl33vfd4abm" +DEFAULT_TRANSACTION_WAIT_TIMEOUT = 60.0 -def transact(ledger_api: LedgerApi, crypto: Crypto, tx: Dict) -> Dict: +def transact( + ledger_api: LedgerApi, + crypto: Crypto, + tx: Dict, + max_retries: int = 5, + sleep: float = 5.0, + timeout: Optional[float] = None, +) -> Dict: """Make a transaction and return a receipt""" - + retries = 0 + tx_receipt = None tx_signed = crypto.sign_transaction(transaction=tx) tx_digest = ledger_api.send_signed_transaction(tx_signed=tx_signed) - - return ledger_api.get_transaction_receipt(tx_digest=tx_digest) + deadline = datetime.now().timestamp() + ( + timeout or DEFAULT_TRANSACTION_WAIT_TIMEOUT + ) + while ( + tx_receipt is None + and retries < max_retries + and deadline >= datetime.now().timestamp() + ): + try: + return ledger_api.api.eth.get_transaction_receipt(tx_digest) + except Web3Exception: # pylint: disable=broad-except + time.sleep(sleep) + raise TimeoutError("Timed out when waiting for transaction to go through") def sort_service_dependency_metadata( @@ -78,208 +100,298 @@ def sort_service_dependency_metadata( return ids_sorted, slots_sorted, securities_sorted -def wait_for_component_to_mint( - token_retriever: Callable[[], Optional[int]], - timeout: Optional[float] = None, - sleep: float = 1.0, -) -> int: - """Wait for service activation.""" - - timeout = timeout or EVENT_VERIFICATION_TIMEOUT - deadline = datetime.datetime.now() + datetime.timedelta(seconds=timeout) - while datetime.datetime.now() < deadline: - token_id = token_retriever() - if token_id is not None: - return token_id - time.sleep(sleep) - - raise TimeoutError("Could not retrieve the token in given time limit.") - - -def mint_component( # pylint: disable=too-many-arguments - ledger_api: LedgerApi, - crypto: Crypto, - metadata_hash: str, - component_type: UnitType, - chain_type: ChainType, - owner: Optional[str] = None, - dependencies: Optional[List[int]] = None, - timeout: Optional[float] = None, -) -> Optional[int]: - """Publish component on-chain.""" - - if dependencies is not None: - dependencies = sorted(set(dependencies)) - - try: - owner = ledger_api.api.toChecksumAddress(owner or crypto.address) - except ValueError as e: # pragma: nocover - raise ComponentMintFailed(f"Invalid owner address {owner}") from e - - try: - tx = registry_contracts.registries_manager.get_create_transaction( - ledger_api=ledger_api, - contract_address=ContractConfigs.get( - REGISTRIES_MANAGER_CONTRACT.name - ).contracts[chain_type], - owner=owner, - sender=crypto.address, - component_type=component_type, - metadata_hash=metadata_hash, - dependencies=dependencies, - raise_on_try=True, +class MintManager: + """Mint helper.""" + + def __init__( # pylint: disable=too-many-arguments + self, + ledger_api: LedgerApi, + crypto: Crypto, + chain_type: ChainType, + dry_run: bool = False, + timeout: Optional[float] = None, + retries: Optional[int] = None, + sleep: Optional[float] = None, + ) -> None: + """Initialize object.""" + self.crypto = crypto + self.ledger_api = ledger_api + self.chain_type = chain_type + self.timeout = timeout + self.retries = retries + self.sleep = sleep + self.dry_run = dry_run + + def _transact( + self, + method: Callable, + kwargs: Dict, + build_tx_ctr: str, + event: str, + process_receipt_ctr: PublicId, + ) -> List[Dict]: + """Auxiliary method for minting components.""" + tx_settler = TxSettler( + ledger_api=self.ledger_api, + crypto=self.crypto, + chain_type=self.chain_type, + timeout=self.timeout, + retries=self.retries, + sleep=self.sleep, ) - transact( - ledger_api=ledger_api, - crypto=crypto, - tx=tx, + receipt = tx_settler.transact( + method=method, + contract=build_tx_ctr, + kwargs=kwargs, + dry_run=self.dry_run, ) - except RequestsConnectionError as e: - raise ComponentMintFailed("Cannot connect to the given RPC") from e - - try: - if component_type == UnitType.COMPONENT: - - def token_retriever() -> bool: - """Retrieve token""" - return registry_contracts.component_registry.filter_token_id_from_emitted_events( - ledger_api=ledger_api, - contract_address=ContractConfigs.get( - COMPONENT_REGISTRY_CONTRACT.name - ).contracts[chain_type], - metadata_hash=metadata_hash, - ) - - else: - - def token_retriever() -> bool: - """Retrieve token""" - return registry_contracts.agent_registry.filter_token_id_from_emitted_events( - ledger_api=ledger_api, - contract_address=ContractConfigs.get( - AGENT_REGISTRY_CONTRACT.name - ).contracts[chain_type], - metadata_hash=metadata_hash, - ) - - return wait_for_component_to_mint( - token_retriever=token_retriever, timeout=timeout + if self.dry_run: + print("=== Dry run output ===") + print("Method: " + str(method).split(" ")[2]) + print( + f"Contract: {ContractConfigs.get(name=build_tx_ctr).contracts[self.chain_type]}" + ) + print("Kwargs: ") + for key, val in kwargs.items(): + print(f" {key}: {val}") + print("Transaction: ") + for key, val in receipt.items(): + print(f" {key}: {val}") + return [] + events = tx_settler.process( + event=event, + receipt=receipt, + contract=process_receipt_ctr, + ).get("events") + return cast(List[Dict], events) + + def validate_address(self, address: str) -> str: + """Validate address string.""" + try: + return self.ledger_api.api.to_checksum_address(address) + except ValueError as e: # pragma: nocover + raise ComponentMintFailed(f"Invalid owner address {address}") from e + + def mint_component( + self, + metadata_hash: str, + component_type: UnitType, + owner: Optional[str] = None, + dependencies: Optional[List[int]] = None, + ) -> Optional[int]: + """Publish component on-chain.""" + owner = self.validate_address(owner or self.crypto.address) + if dependencies is not None: + dependencies = sorted(set(dependencies)) + + events = self._transact( + method=registry_contracts.registries_manager.get_create_transaction, + build_tx_ctr=REGISTRIES_MANAGER_CONTRACT.name, + kwargs=dict( + owner=owner, + component_type=component_type, + metadata_hash=metadata_hash, + sender=self.crypto.address, + dependencies=dependencies, + ), + event="CreateUnit", + process_receipt_ctr=( + COMPONENT_REGISTRY_CONTRACT + if component_type == UnitType.COMPONENT + else AGENT_REGISTRY_CONTRACT + ), ) + for event in events: + if ( + "unitHash" in event["args"] + and event["args"]["unitHash"].hex() == metadata_hash[2:] + ): + return event["args"]["unitId"] + return None + + def update_component( + self, metadata_hash: str, unit_id: int, component_type: UnitType + ) -> Optional[int]: + """Update component on-chain.""" + + events = self._transact( + method=registry_contracts.registries_manager.get_update_hash_transaction, + build_tx_ctr=REGISTRIES_MANAGER_CONTRACT.name, + kwargs=dict( + unit_id=unit_id, + component_type=component_type, + metadata_hash=metadata_hash, + sender=self.crypto.address, + ), + event="UpdateUnitHash", + process_receipt_ctr=( + COMPONENT_REGISTRY_CONTRACT + if component_type == UnitType.COMPONENT + else AGENT_REGISTRY_CONTRACT + ), + ) + for event in events: + if ( + "unitHash" in event["args"] + and event["args"]["unitHash"].hex() == metadata_hash[2:] + ): + return event["args"]["unitId"] + return None + + def mint_service( # pylint: disable=too-many-arguments + self, + metadata_hash: str, + agent_ids: List[int], + number_of_slots_per_agent: List[int], + cost_of_bond_per_agent: List[int], + threshold: int, + token: Optional[str] = None, + owner: Optional[str] = None, + ) -> Optional[int]: + """Publish component on-chain.""" + + if len(agent_ids) == 0: + raise InvalidMintParameter("Please provide at least one agent id") + + if len(number_of_slots_per_agent) == 0: + raise InvalidMintParameter("Please for provide number of slots for agents") + + if len(cost_of_bond_per_agent) == 0: + raise InvalidMintParameter("Please for provide cost of bond for agents") + + if ( + len(agent_ids) != len(number_of_slots_per_agent) + or len(agent_ids) != len(cost_of_bond_per_agent) + or len(number_of_slots_per_agent) != len(cost_of_bond_per_agent) + ): + raise InvalidMintParameter( + "Make sure the number of agent ids, number of slots for agents and cost of bond for agents match" + ) - except RequestsConnectionError as e: - raise FailedToRetrieveTokenId( - "Connection interrupted while waiting for the unitId emit event" - ) from e - except TimeoutError as e: - raise FailedToRetrieveTokenId(str(e)) from e - - -def mint_service( # pylint: disable=too-many-arguments - ledger_api: LedgerApi, - crypto: Crypto, - metadata_hash: str, - chain_type: ChainType, - agent_ids: List[int], - number_of_slots_per_agent: List[int], - cost_of_bond_per_agent: List[int], - threshold: int, - owner: Optional[str] = None, - timeout: Optional[float] = None, -) -> Optional[int]: - """Publish component on-chain.""" - - if len(agent_ids) == 0: - raise InvalidMintParameter("Please provide at least one agent id") + if any(map(lambda x: x == 0, number_of_slots_per_agent)): + raise InvalidMintParameter("Number of slots cannot be zero") - if len(number_of_slots_per_agent) == 0: - raise InvalidMintParameter("Please for provide number of slots for agents") + if any(map(lambda x: x == 0, cost_of_bond_per_agent)): + raise InvalidMintParameter("Cost of bond cannot be zero") - if len(cost_of_bond_per_agent) == 0: - raise InvalidMintParameter("Please for provide cost of bond for agents") + number_of_agent_instances = sum(number_of_slots_per_agent) + if threshold < (ceil((number_of_agent_instances * 2 + 1) / 3)): + raise InvalidMintParameter( + "The threshold value should at least be greater than or equal to ceil((n * 2 + 1) / 3), " + "n is total number of agent instances in the service" + ) - if ( - len(agent_ids) != len(number_of_slots_per_agent) - or len(agent_ids) != len(cost_of_bond_per_agent) - or len(number_of_slots_per_agent) != len(cost_of_bond_per_agent) - ): - raise InvalidMintParameter( - "Make sure the number of agent ids, number of slots for agents and cost of bond for agents match" + ( + agent_ids, + number_of_slots_per_agent, + cost_of_bond_per_agent, + ) = sort_service_dependency_metadata( + agent_ids=agent_ids, + number_of_slots_per_agents=number_of_slots_per_agent, + cost_of_bond_per_agent=cost_of_bond_per_agent, ) - if any(map(lambda x: x == 0, number_of_slots_per_agent)): - raise InvalidMintParameter("Number of slots cannot be zero") + owner = self.validate_address(owner or self.crypto.address) + agent_params = [ + [n, c] for n, c in zip(number_of_slots_per_agent, cost_of_bond_per_agent) + ] + + events = self._transact( + method=registry_contracts.service_manager.get_create_transaction, + build_tx_ctr=SERVICE_MANAGER_CONTRACT.name, + kwargs=dict( + metadata_hash=metadata_hash, + agent_params=agent_params, + agent_ids=agent_ids, + threshold=threshold, + token=token, + owner=owner, + sender=self.crypto.address, + ), + event="CreateService", + process_receipt_ctr=SERVICE_REGISTRY_CONTRACT, + ) + for event in events: + if "serviceId" in event["args"]: + return event["args"]["serviceId"] + return None + + def update_service( # pylint: disable=too-many-arguments + self, + metadata_hash: str, + service_id: int, + agent_ids: List[int], + number_of_slots_per_agent: List[int], + cost_of_bond_per_agent: List[int], + threshold: int, + token: Optional[str] = None, + ) -> Optional[int]: + """Publish component on-chain.""" + + if len(agent_ids) == 0: + raise InvalidMintParameter("Please provide at least one agent id") + + if len(number_of_slots_per_agent) == 0: + raise InvalidMintParameter("Please for provide number of slots for agents") + + if len(cost_of_bond_per_agent) == 0: + raise InvalidMintParameter("Please for provide cost of bond for agents") + + if ( + len(agent_ids) != len(number_of_slots_per_agent) + or len(agent_ids) != len(cost_of_bond_per_agent) + or len(number_of_slots_per_agent) != len(cost_of_bond_per_agent) + ): + raise InvalidMintParameter( + "Make sure the number of agent ids, number of slots for agents and cost of bond for agents match" + ) - if any(map(lambda x: x == 0, cost_of_bond_per_agent)): - raise InvalidMintParameter("Cost of bond cannot be zero") + if any(map(lambda x: x == 0, number_of_slots_per_agent)): + raise InvalidMintParameter("Number of slots cannot be zero") - number_of_agent_instances = sum(number_of_slots_per_agent) - if threshold < (ceil((number_of_agent_instances * 2 + 1) / 3)): - raise InvalidMintParameter( - "The threshold value should at least be greater than or equal to ceil((n * 2 + 1) / 3), " - "n is total number of agent instances in the service" - ) + if any(map(lambda x: x == 0, cost_of_bond_per_agent)): + raise InvalidMintParameter("Cost of bond cannot be zero") - ( - agent_ids, - number_of_slots_per_agent, - cost_of_bond_per_agent, - ) = sort_service_dependency_metadata( - agent_ids=agent_ids, - number_of_slots_per_agents=number_of_slots_per_agent, - cost_of_bond_per_agent=cost_of_bond_per_agent, - ) + number_of_agent_instances = sum(number_of_slots_per_agent) + if threshold < (ceil((number_of_agent_instances * 2 + 1) / 3)): + raise InvalidMintParameter( + "The threshold value should at least be greater than or equal to ceil((n * 2 + 1) / 3), " + "n is total number of agent instances in the service" + ) - agent_params = [ - [n, c] for n, c in zip(number_of_slots_per_agent, cost_of_bond_per_agent) - ] - - try: - owner = ledger_api.api.toChecksumAddress(owner or crypto.address) - except ValueError as e: - raise ComponentMintFailed(f"Invalid owner address {owner}") from e - - try: - tx = registry_contracts.service_manager.get_create_transaction( - ledger_api=ledger_api, - contract_address=ContractConfigs.get( - SERVICE_MANAGER_CONTRACT.name - ).contracts[chain_type], - owner=owner, - sender=crypto.address, - metadata_hash=metadata_hash, + ( + agent_ids, + number_of_slots_per_agent, + cost_of_bond_per_agent, + ) = sort_service_dependency_metadata( agent_ids=agent_ids, - agent_params=agent_params, - threshold=threshold, - raise_on_try=True, - ) - transact( - ledger_api=ledger_api, - crypto=crypto, - tx=tx, + number_of_slots_per_agents=number_of_slots_per_agent, + cost_of_bond_per_agent=cost_of_bond_per_agent, ) - except RequestsConnectionError as e: - raise ComponentMintFailed("Cannot connect to the given RPC") from e - - try: - - def token_retriever() -> bool: - """Retrieve token""" - return ( - registry_contracts.service_registry.filter_token_id_from_emitted_events( - ledger_api=ledger_api, - contract_address=ContractConfigs.get( - SERVICE_REGISTRY_CONTRACT.name - ).contracts[chain_type], - ) - ) - return wait_for_component_to_mint( - token_retriever=token_retriever, timeout=timeout + agent_params = [ + [n, c] for n, c in zip(number_of_slots_per_agent, cost_of_bond_per_agent) + ] + + events = self._transact( + method=registry_contracts.service_manager.get_update_transaction, + build_tx_ctr=SERVICE_MANAGER_CONTRACT.name, + kwargs=dict( + service_id=service_id, + sender=self.crypto.address, + metadata_hash=metadata_hash, + agent_ids=agent_ids, + agent_params=agent_params, + threshold=threshold, + token=token, + ), + event="UpdateService", + process_receipt_ctr=SERVICE_REGISTRY_CONTRACT, ) - - except RequestsConnectionError as e: - raise FailedToRetrieveTokenId( - "Connection interrupted while waiting for the unitId emit event" - ) from e - except TimeoutError as e: - raise FailedToRetrieveTokenId(str(e)) from e + for event in events: + if ( + "configHash" in event["args"] + and event["args"]["configHash"].hex() == metadata_hash[2:] + ): + return event["args"]["serviceId"] + return None diff --git a/autonomy/chain/service.py b/autonomy/chain/service.py index 1b23b0e4c6..f4f474da20 100644 --- a/autonomy/chain/service.py +++ b/autonomy/chain/service.py @@ -19,35 +19,61 @@ """Helper functions to manage on-chain services""" -import datetime +import binascii import time -from typing import Callable, Dict, List, Optional, Tuple +from enum import Enum +from typing import Callable, Dict, List, Optional, Tuple, cast from aea.crypto.base import Crypto, LedgerApi -from requests.exceptions import ConnectionError as RequestsConnectionError -from web3.exceptions import ContractLogicError +from hexbytes import HexBytes from autonomy.chain.base import ServiceState, registry_contracts from autonomy.chain.config import ChainType, ContractConfigs from autonomy.chain.constants import ( - EVENT_VERIFICATION_TIMEOUT, - GNOSIS_SAFE_MULTISIG_CONTRACT, + ERC20_CONTRACT, + GNOSIS_SAFE_PROXY_FACTORY_CONTRACT, + GNOSIS_SAFE_SAME_ADDRESS_MULTISIG_CONTRACT, + MULTISEND_CONTRACT, SERVICE_MANAGER_CONTRACT, SERVICE_REGISTRY_CONTRACT, + SERVICE_REGISTRY_TOKEN_UTILITY_CONTRACT, ) from autonomy.chain.exceptions import ( + ChainInteractionError, InstanceRegistrationFailed, ServiceDeployFailed, ServiceRegistrationFailed, + TerminateServiceFailed, + UnbondServiceFailed, ) from autonomy.chain.mint import transact +from autonomy.chain.tx import TxSettler -DEFAULT_DEPLOY_PAYLOAD = "0x" +NULL_ADDRESS = "0x0000000000000000000000000000000000000000" +DEFAULT_FALLBACK_HANDLER = "0xf48f2b2d2a534e402487b3ee7c18c33aec0fe5e4" +DEFAULT_DEPLOY_PAYLOAD = "0x0000000000000000000000000000000000000000{fallback_handler}000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" ServiceInfo = Tuple[int, str, bytes, int, int, int, int, List[int]] +class MultiSendOperation(Enum): + """Operation types.""" + + CALL = 0 + DELEGATE_CALL = 1 + + +def get_delployment_payload(fallback_handler: Optional[str] = None) -> str: + """Calculates deployment payload.""" + return ( + DEFAULT_DEPLOY_PAYLOAD.format( + fallback_handler=(fallback_handler or DEFAULT_FALLBACK_HANDLER)[2:] + ) + + int(time.time()).to_bytes(32, "big").hex() + ) + + def get_agent_instances( ledger_api: LedgerApi, chain_type: ChainType, token_id: int ) -> Dict: @@ -92,285 +118,584 @@ def get_service_info( ) -def wait_for_success_event( - success_check: Callable[[], bool], - message: str = "Timeout error", - timeout: Optional[float] = None, - sleep: float = 1.0, -) -> None: - """Wait for success event.""" - - timeout = timeout or EVENT_VERIFICATION_TIMEOUT - deadline = datetime.datetime.now() + datetime.timedelta(seconds=timeout) - while datetime.datetime.now() < deadline: - if success_check(): - return - time.sleep(sleep) - raise TimeoutError(message) - - -def wait_for_agent_instance_registration( +def get_token_deposit_amount( ledger_api: LedgerApi, chain_type: ChainType, service_id: int, - instances: List[str], - timeout: Optional[float] = None, -) -> None: - """Wait for agent instance registration.""" + agent_id: Optional[int] = None, +) -> int: + """Returns service info.""" + if agent_id is None: + *_, (agent_id, *_) = get_service_info( + ledger_api=ledger_api, chain_type=chain_type, token_id=service_id + ) + return registry_contracts.service_registry_token_utility.get_agent_bond( + ledger_api=ledger_api, + contract_address=ContractConfigs.get( + SERVICE_REGISTRY_TOKEN_UTILITY_CONTRACT.name + ).contracts[chain_type], + service_id=service_id, + agent_id=agent_id, + ).get("bond") - timeout = timeout or EVENT_VERIFICATION_TIMEOUT - deadline = datetime.datetime.now() + datetime.timedelta(seconds=timeout) - instance_check = set(instances) - while datetime.datetime.now() < deadline: - successful_instances = ( - registry_contracts.service_registry.verify_agent_instance_registration( +def get_activate_registration_amount( + ledger_api: LedgerApi, + chain_type: ChainType, + service_id: int, + agents: List[int], +) -> int: + """Get activate registration amount.""" + agent_to_deposit = {} + amount = 0 + for agent in agents: + if agent not in agent_to_deposit: + agent_to_deposit[agent] = get_token_deposit_amount( ledger_api=ledger_api, - contract_address=ContractConfigs.get( - SERVICE_REGISTRY_CONTRACT.name - ).contracts[chain_type], + chain_type=chain_type, service_id=service_id, - instance_check=instance_check, + agent_id=agent, ) - ) + amount += agent_to_deposit[agent] + return amount - instance_check = instance_check.difference(successful_instances) - if len(instance_check) == 0: - return - raise TimeoutError( - f"Could not verify the instance registration for {instance_check} in given time" +def is_service_token_secured( + ledger_api: LedgerApi, + chain_type: ChainType, + service_id: int, +) -> bool: + """Check if the service is token secured.""" + response = ( + registry_contracts.service_registry_token_utility.is_token_secured_service( + ledger_api=ledger_api, + contract_address=ContractConfigs.get( + SERVICE_REGISTRY_TOKEN_UTILITY_CONTRACT.name + ).contracts[chain_type], + service_id=service_id, + ) ) + return response["is_token_secured_service"] -def activate_service( +def approve_erc20_usage( # pylint: disable=too-many-arguments, too-many-locals ledger_api: LedgerApi, crypto: Crypto, chain_type: ChainType, - service_id: int, + spender: str, + amount: int, + sender: str, + dry_run: bool = False, timeout: Optional[float] = None, + retries: Optional[int] = None, + sleep: Optional[float] = None, ) -> None: - """ - Activate service. + """Approve ERC20 token usage.""" + tx_settler = TxSettler( + chain_type=chain_type, + ledger_api=ledger_api, + crypto=crypto, + timeout=timeout, + retries=retries, + sleep=sleep, + ) + method = registry_contracts.erc20.get_approve_tx + contract = ERC20_CONTRACT.name + kwargs = dict( + spender=spender, + amount=amount, + sender=sender, + ) + receipt = tx_settler.transact( + method=method, + contract=contract, + kwargs=kwargs, + ) + if dry_run: # pragma: nocover + print("=== Dry run output ===") + print("Method: " + str(method).split(" ")[2]) + print(f"Contract: {ContractConfigs.get(name=contract).contracts[chain_type]}") + print("Kwargs: ") + for key, val in kwargs.items(): + print(f" {key}: {val}") + print("Transaction: ") + for key, val in receipt.items(): + print(f" {key}: {val}") + return + events = cast( + List[Dict], + tx_settler.process( + event="Approval", + receipt=receipt, + contract=ERC20_CONTRACT, + ).get("events"), + ) + for event in events: + if event["args"]["spender"] == spender: + return + raise ChainInteractionError("Funds approval request failed") + + +class ServiceManager: + """Service manager.""" + + def __init__( # pylint: disable=too-many-arguments + self, + ledger_api: LedgerApi, + crypto: Crypto, + chain_type: ChainType, + dry_run: bool = False, + timeout: Optional[float] = None, + retries: Optional[int] = None, + sleep: Optional[float] = None, + ) -> None: + """Initialize object.""" + self.ledger_api = ledger_api + self.crypto = crypto + self.chain_type = chain_type + self.timeout = timeout + self.retries = retries + self.sleep = sleep + self.dry_run = dry_run + + def _transact( # pylint: disable=too-many-arguments + self, + method: Callable, + kwargs: Dict, + build_tx_ctr: str, + event: str, + service_id: int, + exception: Exception, + ) -> None: + """Auxiliary method for managing services on-chain.""" + tx_settler = TxSettler( + ledger_api=self.ledger_api, + crypto=self.crypto, + chain_type=self.chain_type, + timeout=self.timeout, + retries=self.retries, + sleep=self.sleep, + ) + receipt = tx_settler.transact( + method=method, + contract=build_tx_ctr, + kwargs=kwargs, + dry_run=self.dry_run, + ) + if self.dry_run: + print("=== Dry run output ===") + print("Method: " + str(method).split(" ")[2]) + print( + f"Contract: {ContractConfigs.get(name=build_tx_ctr).contracts[self.chain_type]}" + ) + print("Kwargs: ") + for key, val in kwargs.items(): + print(f" {key}: {val}") + print("Transaction: ") + for key, val in receipt.items(): + print(f" {key}: {val}") + return + events = cast( + List[Dict], + tx_settler.process( + event=event, + receipt=receipt, + contract=SERVICE_REGISTRY_CONTRACT, + ).get("events"), + ) + for _event in events: + if _event["args"]["serviceId"] == service_id: + return + raise exception + + def get_service_info(self, token_id: int) -> ServiceInfo: + """ + Returns service info. + + :param token_id: Token ID pointing to the on-chain service + :returns: security deposit, multisig address, IPFS hash for config, + threshold, max number of agent instances, number of agent instances, + service state, list of cannonical agents + """ + + return get_service_info( + ledger_api=self.ledger_api, + chain_type=self.chain_type, + token_id=token_id, + ) - Once you have minted the service on-chain, you'll have to activate the service - before you can proceed further. + def activate(self, service_id: int) -> None: + """ + Activate service. - :param ledger_api: `aea.crypto.LedgerApi` object for interacting with the chain - :param crypto: `aea.crypto.Crypto` object which has a funded key - :param chain_type: Chain type - :param service_id: Service ID retrieved after minting a service - :param timeout: Time to wait for activation event to emit - """ + Once you have minted the service on-chain, you'll have to activate the service + before you can proceed further. - (cost_of_bond, *_, service_state, _,) = get_service_info( - ledger_api=ledger_api, chain_type=chain_type, token_id=service_id - ) + :param service_id: Service ID retrieved after minting a service + """ - if service_state == ServiceState.NON_EXISTENT.value: - raise ServiceRegistrationFailed("Service does not exist") + ( + cost_of_bond, + *_, + service_state, + _, + ) = self.get_service_info(token_id=service_id) - if service_state != ServiceState.PRE_REGISTRATION.value: - raise ServiceRegistrationFailed("Service must be inactive") + if service_state == ServiceState.NON_EXISTENT.value: + raise ServiceRegistrationFailed("Service does not exist") - try: - tx = registry_contracts.service_manager.get_activate_registration_transaction( - ledger_api=ledger_api, - contract_address=ContractConfigs.get( - SERVICE_MANAGER_CONTRACT.name - ).contracts[chain_type], - owner=crypto.address, + if service_state != ServiceState.PRE_REGISTRATION.value: + raise ServiceRegistrationFailed("Service must be inactive") + + self._transact( + method=registry_contracts.service_manager.get_activate_registration_transaction, + build_tx_ctr=SERVICE_MANAGER_CONTRACT.name, + kwargs=dict( + owner=self.crypto.address, + service_id=service_id, + security_deposit=cost_of_bond, + ), + event="ActivateRegistration", service_id=service_id, - security_deposit=cost_of_bond, - raise_on_try=True, + exception=ServiceRegistrationFailed("Could not verify activation event"), ) - transact(ledger_api=ledger_api, crypto=crypto, tx=tx) - except RequestsConnectionError as e: - raise ServiceRegistrationFailed( - "Service activation failed; Error connecting to the RPC" - ) from e - except ContractLogicError as e: - raise ServiceRegistrationFailed(f"Service activation failed; {e}") from e - - try: - - def success_check() -> bool: - """Success check""" - return ( - registry_contracts.service_registry.verify_service_has_been_activated( - ledger_api=ledger_api, - contract_address=ContractConfigs.get( - SERVICE_REGISTRY_CONTRACT.name - ).contracts[chain_type], - service_id=service_id, - ) + + def register_instance( + self, + service_id: int, + instances: List[str], + agent_ids: List[int], + ) -> None: + """ + Register instance. + + Once you have a service with an active registration, you can register agent + which will be a part of the service deployment. Using this method you can + register maximum N amounts per agents, N being the number of slots for an agent + with agent id being `agent_id`. + + Make sure the instance address you provide is not already a part of any service + and not as same as the service owner. + + :param service_id: Service ID retrieved after minting a service + :param instances: Address of the agent instance + :param agent_ids: Agent ID of the agent that you want this instance to be a part + of when deployed + """ + + if len(agent_ids) != len(instances): + raise InstanceRegistrationFailed( + "Number of agent instances and agent IDs needs to be same" ) - wait_for_success_event( - success_check=success_check, - message="Could not verify the service activation in given time", - timeout=timeout, + ( + cost_of_bond, + *_, + service_state, + _, + ) = self.get_service_info(token_id=service_id) + + if service_state == ServiceState.NON_EXISTENT.value: + raise InstanceRegistrationFailed("Service does not exist") + + if service_state != ServiceState.ACTIVE_REGISTRATION.value: + raise InstanceRegistrationFailed("Service needs to be in active state") + + security_deposit = cost_of_bond * len(agent_ids) + self._transact( + method=registry_contracts.service_manager.get_register_instance_transaction, + build_tx_ctr=SERVICE_MANAGER_CONTRACT.name, + kwargs=dict( + owner=self.crypto.address, + service_id=service_id, + instances=instances, + agent_ids=agent_ids, + security_deposit=security_deposit, + ), + event="RegisterInstance", + service_id=service_id, + exception=InstanceRegistrationFailed("Could not verify registration event"), ) - except TimeoutError as e: - raise ServiceRegistrationFailed(e) from e - -def register_instance( # pylint: disable=too-many-arguments - ledger_api: LedgerApi, - crypto: Crypto, - chain_type: ChainType, - service_id: int, - instances: List[str], - agent_ids: List[int], - timeout: Optional[float] = None, -) -> None: - """ - Register instance. + def deploy( + self, + service_id: int, + fallback_handler: Optional[str] = None, + reuse_multisig: bool = False, + ) -> None: + """ + Deploy service. + + Using this method you can deploy a service on-chain once you have activated + the service and registered the required agent instances. + + :param service_id: Service ID retrieved after minting a service + :param fallback_handler: Fallback handler address for gnosis safe multisig + :param reuse_multisig: Use multisig from the previous deployment + """ + + ( + *_, + service_state, + _, + ) = self.get_service_info(token_id=service_id) + + if service_state == ServiceState.NON_EXISTENT.value: + raise ServiceDeployFailed("Service does not exist") + + if service_state != ServiceState.FINISHED_REGISTRATION.value: + raise ServiceDeployFailed( + "Service needs to be in finished registration state" + ) - Once you have a service with an active registration, you can register agent - which will be a part of the service deployment. Using this method you can - register maximum N amounts per agents, N being the number of slots for an agent - with agent id being `agent_id`. + if reuse_multisig: + _deployment_payload, error = get_reuse_multisig_payload( + ledger_api=self.ledger_api, + crypto=self.crypto, + chain_type=self.chain_type, + service_id=service_id, + ) + if _deployment_payload is None: + raise ServiceDeployFailed(error) + deployment_payload = _deployment_payload + gnosis_safe_multisig = ContractConfigs.get( + GNOSIS_SAFE_SAME_ADDRESS_MULTISIG_CONTRACT.name + ).contracts[self.chain_type] + else: + deployment_payload = get_delployment_payload( + fallback_handler=fallback_handler + ) + gnosis_safe_multisig = ContractConfigs.get( + GNOSIS_SAFE_PROXY_FACTORY_CONTRACT.name + ).contracts[self.chain_type] + + self._transact( + method=registry_contracts.service_manager.get_service_deploy_transaction, + kwargs=dict( + owner=self.crypto.address, + service_id=service_id, + gnosis_safe_multisig=gnosis_safe_multisig, + deployment_payload=deployment_payload, + ), + build_tx_ctr=SERVICE_MANAGER_CONTRACT.name, + event="DeployService", + service_id=service_id, + exception=ServiceDeployFailed("Could not verify the deploy event."), + ) - Make sure the instance address you provide is not already a part of any service - and not as same as the service owner. + def terminate(self, service_id: int) -> None: + """ + Terminate service. - :param ledger_api: `aea.crypto.LedgerApi` object for interacting with the chain - :param crypto: `aea.crypto.Crypto` object which has a funded key - :param chain_type: Chain type - :param service_id: Service ID retrieved after minting a service - :param instances: Address of the agent instance - :param agent_ids: Agent ID of the agent that you want this instance to be a part - of when deployed - :param timeout: Time to wait for register instance event to emit - """ + Using this method you can terminate a service on-chain once you have activated + the service and registered the required agent instances. - if len(agent_ids) != len(instances): - raise InstanceRegistrationFailed( - "Number of agent instances and agent IDs needs to be same" - ) + :param service_id: Service ID retrieved after minting a service + """ - (cost_of_bond, *_, service_state, _,) = get_service_info( - ledger_api=ledger_api, - chain_type=chain_type, - token_id=service_id, - ) + ( + *_, + service_state, + _, + ) = self.get_service_info(token_id=service_id) - if service_state == ServiceState.NON_EXISTENT.value: - raise InstanceRegistrationFailed("Service does not exist") + if service_state == ServiceState.NON_EXISTENT.value: + raise TerminateServiceFailed("Service does not exist") - if service_state != ServiceState.ACTIVE_REGISTRATION.value: - raise InstanceRegistrationFailed("Service needs to be in active state") + if service_state == ServiceState.PRE_REGISTRATION.value: + raise TerminateServiceFailed("Service not active") - security_deposit = cost_of_bond * len(agent_ids) + if service_state == ServiceState.TERMINATED_BONDED.value: + raise TerminateServiceFailed("Service already terminated") - try: - tx = registry_contracts.service_manager.get_register_instance_transaction( - ledger_api=ledger_api, - contract_address=ContractConfigs.get( - SERVICE_MANAGER_CONTRACT.name - ).contracts[chain_type], - owner=crypto.address, + self._transact( + method=registry_contracts.service_manager.get_terminate_service_transaction, + kwargs=dict( + owner=self.crypto.address, + service_id=service_id, + ), + build_tx_ctr=SERVICE_MANAGER_CONTRACT.name, + event="TerminateService", service_id=service_id, - instances=instances, - agent_ids=agent_ids, - security_deposit=security_deposit, - raise_on_try=True, + exception=TerminateServiceFailed("Could not verify the terminate event."), ) - transact(ledger_api=ledger_api, crypto=crypto, tx=tx) - except RequestsConnectionError as e: - raise InstanceRegistrationFailed( - "Instance registration failed; Error connecting to the RPC" - ) from e - except ContractLogicError as e: - raise InstanceRegistrationFailed(f"Instance registration failed; {e}") from e + def unbond(self, service_id: int) -> None: + """ + Unbond service. - try: - wait_for_agent_instance_registration( - ledger_api=ledger_api, - chain_type=chain_type, + Using this method you can unbond a service on-chain once you have terminated + the service. + + :param service_id: Service ID retrieved after minting a service + """ + + ( + *_, + service_state, + _, + ) = self.get_service_info(token_id=service_id) + + if service_state == ServiceState.NON_EXISTENT.value: + raise UnbondServiceFailed("Service does not exist") + + if service_state != ServiceState.TERMINATED_BONDED.value: + raise UnbondServiceFailed("Service needs to be in terminated-bonded state") + + self._transact( + method=registry_contracts.service_manager.get_unbond_service_transaction, + kwargs=dict( + owner=self.crypto.address, + service_id=service_id, + ), + build_tx_ctr=SERVICE_MANAGER_CONTRACT.name, + event="OperatorUnbond", service_id=service_id, - instances=instances, - timeout=timeout, + exception=UnbondServiceFailed("Could not verify the unbond event."), ) - except TimeoutError as e: - raise InstanceRegistrationFailed(e) from e -def deploy_service( +def get_reuse_multisig_payload( # pylint: disable=too-many-locals ledger_api: LedgerApi, crypto: Crypto, chain_type: ChainType, service_id: int, - deployment_payload: Optional[str] = None, - timeout: Optional[float] = None, -) -> None: - """ - Deploy service. - - Using this method you can deploy a service on-chain once you have activated - the service and registered the required agent instances. - - :param ledger_api: `aea.crypto.LedgerApi` object for interacting with the chain - :param crypto: `aea.crypto.Crypto` object which has a funded key - :param chain_type: Chain type - :param service_id: Service ID retrieved after minting a service - :param deployment_payload: Deployment payload to include when making the - deployment transaction - :param timeout: Time to wait for deploy event to emit - """ - deployment_payload = deployment_payload or DEFAULT_DEPLOY_PAYLOAD - (*_, service_state, _,) = get_service_info( +) -> Tuple[Optional[str], Optional[str]]: + """Reuse multisig.""" + _, multisig_address, _, threshold, *_ = get_service_info( ledger_api=ledger_api, chain_type=chain_type, token_id=service_id, ) + if multisig_address == NULL_ADDRESS: + return None, "Cannot reuse multisig, No previous deployment exist!" + + service_owner = crypto.address + multisend_address = ContractConfigs.get(MULTISEND_CONTRACT.name).contracts[ + chain_type + ] + multisig_instance = registry_contracts.gnosis_safe.get_instance( + ledger_api=ledger_api, + contract_address=multisig_address, + ) - if service_state == ServiceState.NON_EXISTENT.value: - raise ServiceDeployFailed("Service does not exist") - - if service_state != ServiceState.FINISHED_REGISTRATION.value: - raise ServiceDeployFailed("Service needs to be in finished registration state") + # Verify if the service was terminated properly or not + old_owners = multisig_instance.functions.getOwners().call() + if len(old_owners) != 1 or service_owner not in old_owners: + return ( + None, + "Service was not terminated properly, the service owner should be the only owner of the safe", + ) - try: - tx = registry_contracts.service_manager.get_service_deploy_transaction( + # Build multisend tx to add new instances as owners + txs = [] + new_owners = cast( + List[str], + get_agent_instances( ledger_api=ledger_api, - contract_address=ContractConfigs.get( - SERVICE_MANAGER_CONTRACT.name - ).contracts[chain_type], - owner=crypto.address, - service_id=service_id, - gnosis_safe_multisig=ContractConfigs.get( - GNOSIS_SAFE_MULTISIG_CONTRACT.name - ).contracts[chain_type], - deployment_payload=deployment_payload, - raise_on_try=True, - ) - transact(ledger_api=ledger_api, crypto=crypto, tx=tx) - except RequestsConnectionError as e: - raise ServiceDeployFailed( - "Service deployment failed; Cannot connect to the RPC" - ) from e - except ContractLogicError as e: - raise ServiceDeployFailed(f"Service deployment failed; {e}") from e - - try: - - def success_check() -> bool: - """Success check""" - return registry_contracts.service_registry.verify_service_has_been_deployed( - ledger_api=ledger_api, - contract_address=ContractConfigs.get( - SERVICE_REGISTRY_CONTRACT.name - ).contracts[chain_type], - service_id=service_id, - ) + chain_type=chain_type, + token_id=service_id, + ).get("agentInstances"), + ) - wait_for_success_event( - success_check=success_check, - message=f"Could not verify the service deployment for service {service_id} in given time", - timeout=timeout, + for _owner in new_owners: + txs.append( + { + "to": multisig_address, + "data": HexBytes( + bytes.fromhex( + multisig_instance.encodeABI( + fn_name="addOwnerWithThreshold", + args=[_owner, 1], + )[2:] + ) + ), + "operation": MultiSendOperation.CALL, + "value": 0, + } ) - except TimeoutError as e: - raise ServiceDeployFailed(e) from e + + txs.append( + { + "to": multisig_address, + "data": HexBytes( + bytes.fromhex( + multisig_instance.encodeABI( + fn_name="removeOwner", + args=[new_owners[0], service_owner, 1], + )[2:] + ) + ), + "operation": MultiSendOperation.CALL, + "value": 0, + } + ) + + txs.append( + { + "to": multisig_address, + "data": HexBytes( + bytes.fromhex( + multisig_instance.encodeABI( + fn_name="changeThreshold", + args=[threshold], + )[2:] + ) + ), + "operation": MultiSendOperation.CALL, + "value": 0, + } + ) + + multisend_tx = registry_contracts.multisend.get_multisend_tx( + ledger_api=ledger_api, + contract_address=multisend_address, + txs=txs, + ) + safe_tx_hash = registry_contracts.gnosis_safe.get_raw_safe_transaction_hash( + ledger_api=ledger_api, + contract_address=multisig_address, + to_address=multisend_address, + value=multisend_tx["value"], + data=multisend_tx["data"], + operation=1, + ).get("tx_hash") + approve_hash_tx = registry_contracts.gnosis_safe.get_approve_hash_tx( + ledger_api=ledger_api, + contract_address=multisig_address, + tx_hash=safe_tx_hash, + sender=crypto.address, + ) + transact( + ledger_api=ledger_api, + crypto=crypto, + tx=approve_hash_tx, + ) + + safe_tx_bytes = binascii.unhexlify(safe_tx_hash[2:]) + owner_to_signature = { + crypto.address: crypto.sign_message( + message=safe_tx_bytes, + is_deprecated_mode=True, + )[2:] + } + signature_bytes = registry_contracts.gnosis_safe.get_packed_signatures( + owners=tuple(old_owners), signatures_by_owner=owner_to_signature + ) + safe_exec_data = multisig_instance.encodeABI( + fn_name="execTransaction", + args=[ + multisend_address, # to address + multisend_tx["value"], # value + multisend_tx["data"], # data + 1, # operation + 0, # safe tx gas + 0, # bas gas + 0, # safe gas price + NULL_ADDRESS, # gas token + NULL_ADDRESS, # refund receiver + signature_bytes, # signatures + ], + ) + payload = multisig_address + safe_exec_data[2:] + return payload, None diff --git a/autonomy/chain/tx.py b/autonomy/chain/tx.py new file mode 100644 index 0000000000..d722ccf7b4 --- /dev/null +++ b/autonomy/chain/tx.py @@ -0,0 +1,200 @@ +# -*- coding: utf-8 -*- +# ------------------------------------------------------------------------------ +# +# Copyright 2023 Valory AG +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# ------------------------------------------------------------------------------ + +"""Tx settlement helper.""" + +import time +from datetime import datetime +from typing import Callable, Dict, Optional, cast + +from aea.configurations.data_types import PublicId +from aea.crypto.base import Crypto, LedgerApi +from requests.exceptions import ConnectionError as RequestsConnectionError + +from autonomy.chain.base import registry_contracts +from autonomy.chain.config import ChainType, ContractConfigs +from autonomy.chain.exceptions import ( + ChainInteractionError, + ChainTimeoutError, + RPCError, + TxBuildError, +) + + +DEFAULT_ON_CHAIN_INTERACT_TIMEOUT = 60.0 +DEFAULT_ON_CHAIN_INTERACT_RETRIES = 5.0 +DEFAULT_ON_CHAIN_INTERACT_SLEEP = 3.0 + +ERRORS_TO_RETRY = ( + "FeeTooLow", + "wrong transaction nonce", + "INTERNAL_ERROR: nonce too low", + "Got empty transaction", + "AlreadyKnown", +) + + +def should_retry(error: str) -> bool: + """Check an error message to check if we should raise an error or retry the tx""" + if "Transaction with hash" in error and "not found" in error: + return True + for _error in ERRORS_TO_RETRY: + if _error in error: + return True + return False + + +def should_reprice(error: str) -> bool: + """Check an error message to check if we should reprice the transaction""" + return "FeeTooLow" in error + + +class TxSettler: + """Tx settlement helper""" + + tx: Optional[Dict] + + def __init__( # pylint: disable=too-many-arguments + self, + ledger_api: LedgerApi, + crypto: Crypto, + chain_type: ChainType, + timeout: Optional[float] = None, + retries: Optional[int] = None, + sleep: Optional[float] = None, + ) -> None: + """Initialize object.""" + self.chain_type = chain_type + self.ledger_api = ledger_api + self.crypto = crypto + self.tx = None + self.timeout = timeout or DEFAULT_ON_CHAIN_INTERACT_TIMEOUT + self.retries = retries or DEFAULT_ON_CHAIN_INTERACT_RETRIES + self.sleep = sleep or DEFAULT_ON_CHAIN_INTERACT_SLEEP + + def build( + self, + method: Callable[[], Dict], + contract: str, + kwargs: Dict, + ) -> Dict: + """Build transaction.""" + return method( # type: ignore + ledger_api=self.ledger_api, + contract_address=ContractConfigs.get(name=contract).contracts[ + self.chain_type + ], + raise_on_try=True, + **kwargs, + ) + + def _repice(self, tx_dict: Dict) -> Dict: + """Reprice transaction.""" + old_price = { + "maxFeePerGas": tx_dict[ # pylint: disable=unsubscriptable-object + "maxFeePerGas" + ], + "maxPriorityFeePerGas": tx_dict[ # pylint: disable=unsubscriptable-object + "maxPriorityFeePerGas" + ], + } + tx_dict.update( + self.ledger_api.try_get_gas_pricing( + old_price=old_price, + ) + ) + return tx_dict + + @staticmethod + def _already_known(error: str) -> bool: + """Check if the transaction is alreade sent""" + return "AlreadyKnown" in error + + def transact( + self, + method: Callable[[], Dict], + contract: str, + kwargs: Dict, + dry_run: bool = False, + ) -> Dict: + """Make a transaction and return a receipt""" + retries = 0 + tx_dict = None + tx_digest = None + already_known = False + deadline = datetime.now().timestamp() + self.timeout + while retries < self.retries and deadline >= datetime.now().timestamp(): + retries += 1 + try: + if not already_known: + tx_dict = tx_dict or self.build( + method=method, + contract=contract, + kwargs=kwargs, + ) + if tx_dict is None: + raise TxBuildError("Got empty transaction") + + # Return transaction dict on dry-run + if dry_run: + return tx_dict + + tx_signed = self.crypto.sign_transaction(transaction=tx_dict) + tx_digest = self.ledger_api.send_signed_transaction( + tx_signed=tx_signed, + raise_on_try=True, + ) + tx_receipt = self.ledger_api.api.eth.get_transaction_receipt( + cast(str, tx_digest) + ) + if tx_receipt is not None: + return tx_receipt + except RequestsConnectionError as e: + raise RPCError("Cannot connect to the given RPC") from e + except Exception as e: # pylint: disable=broad-except + error = str(e) + if self._already_known(error): + already_known = True + continue # pragma: nocover + if not should_retry(error): + raise ChainInteractionError(error) from e + if should_reprice(error): + print("Repricing the transaction...") + tx_dict = self._repice(cast(Dict, tx_dict)) + continue + print(f"Error occured when interacting with chain: {e}; ") + print(f"will retry in {self.sleep}...") + time.sleep(self.sleep) + raise ChainTimeoutError("Timed out when waiting for transaction to go through") + + def process( + self, + event: str, + receipt: Dict, + contract: PublicId, + ) -> Dict: + """Process tx receipt.""" + return registry_contracts.get_contract(contract).get_events( + ledger_api=self.ledger_api, + contract_address=ContractConfigs.get(contract.name).contracts[ + self.chain_type + ], + receipt=receipt, + event=event, + ) diff --git a/autonomy/chain/utils.py b/autonomy/chain/utils.py index 9b5d660aee..48661ab6a4 100644 --- a/autonomy/chain/utils.py +++ b/autonomy/chain/utils.py @@ -19,15 +19,25 @@ """Utility functions.""" from json import JSONDecodeError -from typing import Dict +from typing import Dict, List +from aea.configurations.base import PackageConfiguration from aea.configurations.data_types import PackageId, PublicId from aea.crypto.base import LedgerApi from requests import get as r_get from requests.exceptions import ConnectionError as RequestConnectionError from autonomy.chain.base import registry_contracts +from autonomy.chain.constants import SERVICE_MANAGER_TOKEN_COMPATIBLE_CHAINS from autonomy.chain.exceptions import DependencyError, FailedToRetrieveComponentMetadata +from autonomy.chain.metadata import IPFS_URI_PREFIX +from autonomy.configurations.base import Service + + +def get_ipfs_hash_from_uri(uri: str) -> str: + """Split IPFS hash from the ipfs uri""" + + return uri.replace(IPFS_URI_PREFIX, "") def resolve_component_id( @@ -61,7 +71,7 @@ def resolve_component_id( raise FailedToRetrieveComponentMetadata( "Error connecting to the IPFS gateway" ) from e - except JSONDecodeError as e: # pragma: nocover + except JSONDecodeError as e: raise FailedToRetrieveComponentMetadata( f"Error decoding json data; make sure metadata file for the component exist on the IPFS registry; Dependency ID: {token_id}" ) from e @@ -89,3 +99,92 @@ def parse_public_id_from_metadata(id_string: str) -> PublicId: return PackageId.from_uri_path(id_string).public_id.to_any() raise DependencyError(f"Invalid package name found `{id_string}`") from e + + +def verify_component_dependencies( + ledger_api: LedgerApi, + contract_address: str, + dependencies: List[int], + package_configuration: PackageConfiguration, + skip_hash_check: bool = False, +) -> None: + """Verify package dependencies using on-chain metadata.""" + + public_id_to_hash: Dict[PublicId, List[str]] = {} + + for dependency in package_configuration.package_dependencies: + public_id = dependency.public_id.to_any() + if public_id not in public_id_to_hash: + public_id_to_hash[public_id] = [] + public_id_to_hash[dependency.public_id.to_any()].append(dependency.package_hash) + + for dependency_id in dependencies: + component_metadata = resolve_component_id( + contract_address=contract_address, + ledger_api=ledger_api, + token_id=dependency_id, + ) + component_public_id = parse_public_id_from_metadata(component_metadata["name"]) + if component_public_id not in public_id_to_hash: + raise DependencyError( + f"On chain dependency with id {dependency_id} and public ID {component_public_id} not found in the local package configuration" + ) + + if skip_hash_check and len(public_id_to_hash[component_public_id]) > 0: + public_id_to_hash[component_public_id].pop() + else: + on_chain_hash = get_ipfs_hash_from_uri(uri=component_metadata["code_uri"]) + if on_chain_hash not in public_id_to_hash[component_public_id]: + raise DependencyError( + f"Package hash does not match for the on chain package and the local package; Dependency={dependency_id}" + ) + public_id_to_hash[component_public_id] = [ + _hash + for _hash in public_id_to_hash[component_public_id] + if _hash != on_chain_hash + ] + + if len(public_id_to_hash[component_public_id]) == 0: + del public_id_to_hash[component_public_id] + + if len(public_id_to_hash): + missing_deps = list(map(str, public_id_to_hash.keys())) + raise DependencyError( + f"Please provide on chain ID as dependency for following packages; {missing_deps}" + ) + + +def verify_service_dependencies( + ledger_api: LedgerApi, + contract_address: str, + agent_id: int, + service_configuration: Service, + skip_hash_check: bool = False, +) -> None: + """Verify package dependencies using on-chain metadata.""" + + agent = service_configuration.agent + component_metadata = resolve_component_id( + contract_address=contract_address, + ledger_api=ledger_api, + token_id=agent_id, + is_agent=True, + ) + component_public_id = parse_public_id_from_metadata(component_metadata["name"]) + if component_public_id != agent.to_any(): + raise DependencyError( + "On chain ID of the agent does not match with the one in the service configuration" + ) + + if skip_hash_check: + return + + if agent.hash != get_ipfs_hash_from_uri(uri=component_metadata["code_uri"]): + raise DependencyError( + f"Package hash does not match for the on chain package and the local package; Dependency={agent}" + ) + + +def is_service_manager_token_compatible_chain(ledger_api: LedgerApi) -> bool: + """Verify package dependencies using on-chain metadata.""" + return ledger_api.api.eth.chain_id in SERVICE_MANAGER_TOKEN_COMPATIBLE_CHAINS diff --git a/autonomy/cli/analyse.py b/autonomy/cli/analyse.py index 30afeb1bd8..b40964f215 100644 --- a/autonomy/cli/analyse.py +++ b/autonomy/cli/analyse.py @@ -425,6 +425,11 @@ def benchmark(path: Path, block_type: str, period: int, output: Path) -> None: type=PublicIdParameter(), help="Public ID of the service", ) +@click.option( + "--skip-warnings", + is_flag=True, + help="Skip warnings", +) @chain_selection_flag() @pass_ctx def _check_service( @@ -432,6 +437,7 @@ def _check_service( token_id: Optional[int], public_id: Optional[PublicId], chain_type: str, + skip_warnings: bool, ) -> None: """Check deployment readiness of a service""" @@ -450,4 +456,5 @@ def _check_service( public_id=public_id, chain_type=ChainType(chain_type), packages_dir=Path(ctx.registry_path), + skip_warnings=skip_warnings, ) diff --git a/autonomy/cli/build_images.py b/autonomy/cli/build_images.py index 7e8ad8a2e1..1f09f16aa7 100644 --- a/autonomy/cli/build_images.py +++ b/autonomy/cli/build_images.py @@ -19,18 +19,20 @@ """Build images.""" - from pathlib import Path -from typing import Optional +from typing import Optional, Tuple import click -from aea.cli.utils.click_utils import PublicIdParameter, reraise_as_click_exception -from aea.configurations.data_types import PublicId +from aea.cli.utils.click_utils import ( + PublicIdParameter, + PyPiDependency, + reraise_as_click_exception, +) +from aea.configurations.data_types import Dependency, PublicId +from autonomy.cli.helpers.image import build_image as _build_image from autonomy.cli.utils.click_utils import image_author_option -from autonomy.configurations.loader import load_service_config from autonomy.deploy.image import ImageBuildFailed -from autonomy.deploy.image import build_image as _build_image @click.command(name="build-image") @@ -44,13 +46,33 @@ type=click.Path(dir_okay=True), help="Path to service dir.", ) +@click.option( + "-e", + "--extra-dependency", + "extra_dependencies", + type=PyPiDependency(), + help="Provide extra dependency.", + multiple=True, +) @click.option("--version", type=str, help="Specify tag version for the image.") @click.option("--dev", is_flag=True, help="Build development image.", default=False) @click.option("--pull", is_flag=True, help="Pull latest dependencies.", default=False) +@click.option( + "-f", + "--dockerfile", + type=click.Path( + file_okay=True, + dir_okay=False, + exists=False, + ), + help="Specify custom dockerfile for building the agent", +) @image_author_option -def build_image( +def build_image( # pylint: disable=too-many-arguments agent: Optional[PublicId], service_dir: Optional[Path], + dockerfile: Optional[Path], + extra_dependencies: Tuple[Dependency, ...], pull: bool = False, dev: bool = False, version: Optional[str] = None, @@ -58,14 +80,14 @@ def build_image( ) -> None: """Build runtime images for autonomous agents.""" - with reraise_as_click_exception(FileNotFoundError): - if agent is None: - service_dir = Path(service_dir or Path.cwd()).absolute() - service = load_service_config(service_dir) - agent = service.agent - - with reraise_as_click_exception(ImageBuildFailed): - click.echo(f"Building image with agent: {agent}\n") + with reraise_as_click_exception(ImageBuildFailed, FileNotFoundError): _build_image( - agent=agent, pull=pull, dev=dev, version=version, image_author=image_author + agent=agent, + service_dir=service_dir, + extra_dependencies=extra_dependencies, + pull=pull, + dev=dev, + version=version, + image_author=image_author, + dockerfile=dockerfile, ) diff --git a/autonomy/cli/deploy.py b/autonomy/cli/deploy.py index 8e310961b4..89bb957bb1 100644 --- a/autonomy/cli/deploy.py +++ b/autonomy/cli/deploy.py @@ -31,14 +31,21 @@ reraise_as_click_exception, ) from aea.cli.utils.context import Context +from aea.configurations.constants import DEFAULT_ENV_DOTFILE from autonomy.chain.config import ChainType from autonomy.cli.helpers.deployment import ( build_and_deploy_from_token, build_deployment, run_deployment, + stop_deployment, +) +from autonomy.cli.helpers.env import load_env_file +from autonomy.cli.utils.click_utils import ( + PathArgument, + chain_selection_flag, + image_author_option, ) -from autonomy.cli.utils.click_utils import chain_selection_flag, image_author_option from autonomy.constants import DEFAULT_BUILD_FOLDER, DEFAULT_KEYS_FILE from autonomy.deploy.base import NotValidKeysFile from autonomy.deploy.constants import INFO, LOGGING_LEVELS @@ -52,11 +59,26 @@ @click.group(name="deploy") +@click.option( + "--env-file", + type=PathArgument( + exists=True, + dir_okay=False, + file_okay=True, + ), + help="File containing environment variable mappings", +) @click.pass_context def deploy_group( click_context: click.Context, # pylint: disable=unused-argument + env_file: Optional[Path], ) -> None: """Deploy an agent service.""" + dot_env_file = Path.cwd() / DEFAULT_ENV_DOTFILE + if dot_env_file.exists(): + load_env_file(file=dot_env_file) + if env_file is not None: + load_env_file(file=env_file, serialize_json=True) @deploy_group.command(name="build") @@ -165,6 +187,11 @@ def build_deployment_command( # pylint: disable=too-many-arguments, too-many-lo image_author: Optional[str] = None, ) -> None: """Build deployment setup for n agents.""" + if password is not None: # pragma: nocover + click.echo( + "WARNING: `--password` flag has been deprecated, " + "use `OPEN_AUTONOMY_PRIVATE_KEY_PASSWORD` to export the password value" + ) keys_file = Path(keys_file or DEFAULT_KEYS_FILE).absolute() if not keys_file.exists(): @@ -200,7 +227,6 @@ def build_deployment_command( # pylint: disable=too-many-arguments, too-many-lo deployment_type=deployment_type, dev_mode=dev_mode, number_of_agents=number_of_agents, - password=password, packages_dir=packages_dir, open_aea_dir=open_aea_dir, open_autonomy_dir=open_autonomy_dir, @@ -221,6 +247,7 @@ def build_deployment_command( # pylint: disable=too-many-arguments, too-many-lo @click.option( "--build-dir", type=click.Path(), + help="Path to the deployment build directory.", ) @click.option( "--no-recreate", @@ -234,16 +261,38 @@ def build_deployment_command( # pylint: disable=too-many-arguments, too-many-lo default=False, help="Remove containers for services not defined in the Compose file.", ) -def run(build_dir: Path, no_recreate: bool, remove_orphans: bool) -> None: +@click.option( + "--detach", + is_flag=True, + default=False, + help="Run service in the background.", +) +def run( + build_dir: Path, no_recreate: bool, remove_orphans: bool, detach: bool = False +) -> None: """Run deployment.""" build_dir = Path(build_dir or Path.cwd()).absolute() - if not (build_dir / DockerComposeGenerator.output_name).exists(): raise click.ClickException( f"Deployment configuration does not exist @ {build_dir}" ) + run_deployment(build_dir, no_recreate, remove_orphans, detach=detach) - run_deployment(build_dir, no_recreate, remove_orphans) + +@deploy_group.command(name="stop") +@click.option( + "--build-dir", + type=click.Path(), + help="Path to the deployment build directory.", +) +def stop(build_dir: Path) -> None: + """Stop a running deployment.""" + build_dir = Path(build_dir or Path.cwd()).absolute() + if not (build_dir / DockerComposeGenerator.output_name).exists(): + raise click.ClickException( + f"Deployment configuration does not exist @ {build_dir}" + ) + stop_deployment(build_dir=build_dir) @deploy_group.command(name="from-token") @@ -275,6 +324,12 @@ def run(build_dir: Path, no_recreate: bool, remove_orphans: bool) -> None: is_flag=True, help="If set to true, the deployment won't run automatically", ) +@click.option( + "--detach", + is_flag=True, + default=False, + help="Run service in the background.", +) @chain_selection_flag(help_string_format="Use {} chain to resolve the token id.") @click.pass_context @password_option(confirmation_prompt=True) @@ -287,15 +342,20 @@ def run_deployment_from_token( # pylint: disable=too-many-arguments, too-many-l n: Optional[int], deployment_type: str, no_deploy: bool, + detach: bool, aev: bool = False, password: Optional[str] = None, ) -> None: """Run service deployment.""" + if password is not None: # pragma: nocover + click.echo( + "WARNING: `--password` flag has been deprecated, " + "use `OPEN_AUTONOMY_PRIVATE_KEY_PASSWORD` to export the password value" + ) ctx = cast(Context, click_context.obj) ctx.registry_type = REGISTRY_REMOTE keys_file = Path(keys_file or DEFAULT_KEYS_FILE).absolute() - with reraise_as_click_exception( NotValidKeysFile, FileNotFoundError, FileExistsError ): @@ -307,6 +367,6 @@ def run_deployment_from_token( # pylint: disable=too-many-arguments, too-many-l n=n, deployment_type=deployment_type, aev=aev, - password=password, no_deploy=no_deploy, + detach=detach, ) diff --git a/autonomy/cli/fetch.py b/autonomy/cli/fetch.py index 893b78b206..3ffb1cfe3c 100644 --- a/autonomy/cli/fetch.py +++ b/autonomy/cli/fetch.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- # ------------------------------------------------------------------------------ # -# Copyright 2022 Valory AG +# Copyright 2022-2023 Valory AG # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -68,7 +68,7 @@ def fetch( if package_type == AGENT: do_fetch(ctx, public_id, alias) else: - fetch_service(ctx, public_id) + fetch_service(ctx, public_id, alias) except NotAnAgentPackage as e: raise click.ClickException( "Downloaded packages is not an agent package, " diff --git a/autonomy/cli/helpers/analyse.py b/autonomy/cli/helpers/analyse.py index b711e1f49f..438e6268b0 100644 --- a/autonomy/cli/helpers/analyse.py +++ b/autonomy/cli/helpers/analyse.py @@ -57,9 +57,10 @@ from autonomy.chain.config import ChainType, ContractConfigs from autonomy.chain.exceptions import FailedToRetrieveComponentMetadata from autonomy.chain.utils import resolve_component_id -from autonomy.cli.helpers.chain import get_ledger_and_crypto_objects +from autonomy.cli.helpers.chain import OnChainHelper from autonomy.cli.utils.click_utils import sys_path_patch from autonomy.configurations.base import PACKAGE_TYPE_TO_CONFIG_CLASS, Service +from autonomy.constants import ABSTRACT_ROUND_ABCI_SKILL_WITH_HASH def load_package_tree(packages_dir: Path) -> None: @@ -289,6 +290,18 @@ def _load_from_local( ) +def _has_abstract_round_abci_skill_as_dependency(skill_config: SkillConfig) -> bool: + """Check if a skill has a `abstract_round_abci` as a dependency""" + abstract_round_abci_skill = PublicId.from_str( + ABSTRACT_ROUND_ABCI_SKILL_WITH_HASH + ).without_hash() + return any( + map( + lambda x: x.without_hash() == abstract_round_abci_skill, skill_config.skills + ) + ) + + def _get_chained_abci_skill( agent_config: AgentConfig, package_manager: PackageManagerV1, @@ -338,6 +351,10 @@ def _get_chained_abci_skill( if skill_config.is_abstract: continue + # Check if the skill has the `abstract_round_abci` skill as a dependency + if not _has_abstract_round_abci_skill_as_dependency(skill_config=skill_config): + continue + # This statement makes an assumption skills other than the chained/main # abci are defined as abstract return skill_config @@ -380,11 +397,12 @@ def check_service_readiness( # pylint: disable=too-many-locals public_id: Optional[PublicId], chain_type: ChainType, packages_dir: Path, + skip_warnings: bool = False, ) -> None: """Check deployment readiness of a service.""" is_on_chain_check = token_id is not None - ledger_api, _ = get_ledger_and_crypto_objects(chain_type=chain_type) + ledger_api, _ = OnChainHelper.get_ledger_and_crypto_objects(chain_type=chain_type) package_manager = PackageManagerV1.from_dir(packages_dir=packages_dir) ipfs_pins = _get_ipfs_pins(is_on_chain_check=is_on_chain_check) @@ -434,13 +452,18 @@ def check_service_readiness( # pylint: disable=too-many-locals if skill_config is None: raise click.ClickException( - "Please make sure the agent package configuration contains overrides for the chained ABCI app" + "Chained ABCI skill package not found, possible reasons for this failures\n" + "- The agent package does not contain overrides for the chained ABCI app\n" + "- The chained ABCI skill config has `is_abstract` flag set to `true`\n" + "- The chained ABCI skill does not have the `valory/abstract_round_abci` skill as a dependency" ) try: service_analyser = ServiceAnalyser( service_config=service_config, + abci_skill_id=skill_config.public_id, is_on_chain_check=is_on_chain_check, + skip_warnings=skip_warnings, ) service_analyser.check_on_chain_state( @@ -448,11 +471,14 @@ def check_service_readiness( # pylint: disable=too-many-locals chain_type=chain_type, token_id=cast(int, token_id), ) - service_analyser.validate_service_overrides() - service_analyser.validate_agent_overrides(agent_config=agent_config) service_analyser.validate_skill_config(skill_config=skill_config) + service_analyser.validate_agent_overrides(agent_config=agent_config) + service_analyser.validate_agent_override_env_vars(agent_config=agent_config) + service_analyser.validate_service_overrides() + service_analyser.validate_service_override_env_vars() service_analyser.cross_verify_overrides( - agent_config=agent_config, skill_config=skill_config + agent_config=agent_config, + skill_config=skill_config, ) service_analyser.check_agent_dependencies_published( ipfs_pins=ipfs_pins, agent_config=agent_config diff --git a/autonomy/cli/helpers/chain.py b/autonomy/cli/helpers/chain.py index 3cae349b82..8c1f752f16 100644 --- a/autonomy/cli/helpers/chain.py +++ b/autonomy/cli/helpers/chain.py @@ -19,470 +19,908 @@ """On-chain interaction helpers.""" +import binascii from pathlib import Path -from typing import List, Optional, Set, Tuple, cast +from typing import Any, Dict, List, Optional, Tuple, Type, cast import click -from aea.configurations.data_types import PackageId, PackageType +from aea.configurations.base import PackageConfiguration +from aea.configurations.data_types import PackageType from aea.configurations.loader import load_configuration_object from aea.crypto.base import Crypto, LedgerApi from aea.crypto.registries import crypto_registry, ledger_apis_registry from aea.helpers.base import IPFSHash -from aea_ledger_ethereum.ethereum import EthereumApi, EthereumCrypto - -from autonomy.chain.base import UnitType -from autonomy.chain.config import ChainConfigs, ChainType +from texttable import Texttable + +from autonomy.chain.base import ServiceState, UnitType +from autonomy.chain.config import ( + ChainConfigs, + ChainType, + ContractConfig, + ContractConfigs, +) +from autonomy.chain.constants import ( + AGENT_REGISTRY_CONTRACT, + COMPONENT_REGISTRY_CONTRACT, + SERVICE_REGISTRY_CONTRACT, + SERVICE_REGISTRY_TOKEN_UTILITY_CONTRACT, +) from autonomy.chain.exceptions import ( - ComponentMintFailed, - FailedToRetrieveTokenId, - InstanceRegistrationFailed, - InvalidMintParameter, - ServiceDeployFailed, - ServiceRegistrationFailed, + ChainInteractionError, + DependencyError, + FailedToRetrieveComponentMetadata, ) from autonomy.chain.metadata import NFTHashOrPath, publish_metadata -from autonomy.chain.mint import DEFAULT_NFT_IMAGE_HASH -from autonomy.chain.mint import mint_component as _mint_component -from autonomy.chain.mint import mint_service as _mint_service -from autonomy.chain.service import activate_service as _activate_service -from autonomy.chain.service import deploy_service as _deploy_service -from autonomy.chain.service import register_instance as _register_instance -from autonomy.chain.subgraph.client import SubgraphClient, UnitContainer +from autonomy.chain.mint import DEFAULT_NFT_IMAGE_HASH, MintManager +from autonomy.chain.service import ( + ServiceManager, + approve_erc20_usage, + get_activate_registration_amount, + get_agent_instances, + get_service_info, + get_token_deposit_amount, + is_service_token_secured, +) +from autonomy.chain.utils import ( + is_service_manager_token_compatible_chain, + resolve_component_id, + verify_component_dependencies, + verify_service_dependencies, +) from autonomy.configurations.base import PACKAGE_TYPE_TO_CONFIG_CLASS, Service try: - from aea_ledger_ethereum_hwi.exceptions import HWIError - from aea_ledger_ethereum_hwi.hwi import EthereumHWIApi - - HWI_PLUGIN_INSTALLED = True -except ImportError: - HWI_PLUGIN_INSTALLED = False - - -def get_ledger_and_crypto_objects( - chain_type: ChainType, - key: Optional[Path] = None, - password: Optional[str] = None, - hwi: bool = False, -) -> Tuple[LedgerApi, Crypto]: - """Create ledger_api and crypto objects""" - - chain_config = ChainConfigs.get(chain_type=chain_type) - if chain_config.rpc is None: - raise click.ClickException( - f"RPC URL cannot be `None`, " - f"Please set the environment variable for {chain_type.value} chain " - f"using `{ChainConfigs.get_rpc_env_var(chain_type)}` environment variable" - ) - - if hwi and not HWI_PLUGIN_INSTALLED: - raise click.ClickException( - "Hardware wallet plugin not installed, " - "Run `pip3 install open-aea-ledger-ethereum-hwi` to install the plugin" - ) - - identifier = EthereumHWIApi.identifier if hwi else EthereumApi.identifier + from aea_ledger_ethereum.ethereum import EthereumApi, EthereumCrypto + + ETHEREUM_PLUGIN_INSTALLED = True +except ImportError: # pragma: nocover + ETHEREUM_PLUGIN_INSTALLED = False + + +class OnChainHelper: # pylint: disable=too-few-public-methods + """On-chain interaction helper.""" + + def __init__( # pylint: disable=too-many-arguments + self, + chain_type: ChainType, + key: Optional[Path] = None, + password: Optional[str] = None, + hwi: bool = False, + timeout: Optional[float] = None, + retries: Optional[int] = None, + sleep: Optional[float] = None, + dry_run: bool = False, + ) -> None: + """Initialize object.""" + if key is None and not hwi: + raise click.ClickException( + "Please provide key path using `--key` or use `--hwi` if you want to use a hardware wallet" + ) - if key is None: - crypto = crypto_registry.make(identifier) - else: - crypto = EthereumCrypto( - private_key_path=key, + self.chain_type = chain_type + self.ledger_api, self.crypto = self.get_ledger_and_crypto_objects( + chain_type=chain_type, + key=key, password=password, + hwi=hwi, ) + self.timeout = timeout + self.retries = retries + self.sleep = sleep + self.dry_run = dry_run + + @staticmethod + def load_hwi_plugin() -> Type[LedgerApi]: # pragma: nocover + """Load HWI Plugin.""" + try: + from aea_ledger_ethereum_hwi.hwi import ( # pylint: disable=import-outside-toplevel + EthereumHWIApi, + ) - ledger_api = ledger_apis_registry.make( - identifier, - **{ - "address": chain_config.rpc, - "chain_id": chain_config.chain_id, - "is_gas_estimation_enabled": True, - }, - ) + return EthereumHWIApi + except ImportError as e: + raise click.ClickException( + "Hardware wallet plugin not installed, " + "Run `pip3 install open-aea-ledger-ethereum-hwi` to install the plugin" + ) from e + except TypeError as e: + raise click.ClickException( + 'Protobuf compatibility error; Please export PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION="python" ' + "to use the hardware wallet without any issues" + ) from e + + @staticmethod + def load_crypto( + file: Path, + password: Optional[str] = None, + ) -> Crypto: + """Load crypto object.""" + try: + return EthereumCrypto( + private_key_path=file, + password=password, + ) + except (binascii.Error, ValueError) as e: + raise click.ClickException( + "Cannot load private key for following possible reasons\n" + "- Wrong key format\n" + "- Wrong key length\n" + "- Trailing spaces or new line characters" + ) from e + + @classmethod + def get_ledger_and_crypto_objects( + cls, + chain_type: ChainType, + key: Optional[Path] = None, + password: Optional[str] = None, + hwi: bool = False, + ) -> Tuple[LedgerApi, Crypto]: + """Create ledger_api and crypto objects""" + chain_config = ChainConfigs.get(chain_type=chain_type) + identifier = EthereumApi.identifier + + if chain_config.rpc is None: + raise click.ClickException( + f"RPC URL cannot be `None`, " + f"Please set the environment variable for {chain_type.value} chain " + f"using `{ChainConfigs.get_rpc_env_var(chain_type)}` environment variable" + ) + + if hwi: + EthereumHWIApi = cls.load_hwi_plugin() + identifier = EthereumHWIApi.identifier - try: - ledger_api.api.eth.default_account = crypto.address - except HWIError as e: - raise click.ClickException(e.message) - - return ledger_api, crypto - - -def get_on_chain_dependencies( - dependencies: Set[PackageId], - skip_hash_check: bool = False, - use_latest_dependencies: bool = False, -) -> List[int]: - """Get package dependencies""" - not_found = [] - found = [] - subgraph = SubgraphClient() - record: UnitContainer - for dependency in dependencies: - if skip_hash_check: - record = subgraph.getRecordByPackageId( - package_id=dependency, + if not hwi and not ETHEREUM_PLUGIN_INSTALLED: # pragma: nocover + raise click.ClickException( + "Ethereum ledger plugin not installed, " + "Run `pip3 install open-aea-ledger-ethereum` to install the plugin" ) + + if key is None: + crypto = crypto_registry.make(identifier) else: - record = subgraph.getRecordByPackageHash( - package_hash=dependency.package_hash, - ) - - if len(record["units"]) == 0: - not_found.append(dependency) - continue - - units = record["units"] - if len(units) > 1 and use_latest_dependencies: - (*_, unit_record) = sorted(units, key=lambda x: int(x["tokenId"])) - token_id = int(unit_record["tokenId"]) - elif len(units) > 1: - token_ids = [unit["tokenId"] for unit in units] - token_id = int( - click.prompt( - text=( - f"Multiple dependencies found for {dependency.public_id.without_hash()} of type {dependency.package_type}" - "\nPlease choose which dependency to use" - ), - type=click.Choice(choices=token_ids), - ) + crypto = cls.load_crypto( + file=key, + password=password, ) - else: - (unit_record,) = units - token_id = int(unit_record["tokenId"]) - found.append(token_id) + ledger_api = ledger_apis_registry.make( + identifier, + **{ + "address": chain_config.rpc, + "chain_id": chain_config.chain_id, + "is_gas_estimation_enabled": True, + }, + ) - if len(not_found) > 0: - error_message = "\n\t- ".join( - [ - "No on chain registration found for following dependencies", - *map(str, not_found), - ] + if hwi: + # Setting the `LedgerApi.identifier` to `ethereum` for both ledger and + # hardware plugin to interact with the contract. If we use `ethereum_hwi` + # as the ledger identifier the contracts will need ABI configuration for + # the `ethereum_hwi` identifier which means we will have to define hardware + # wallet as the dependency for contract but the hardware wallet plugin + # is meant to be used for CLI tools only so we set the identifier to + # `ethereum` for both ledger and hardware wallet plugin + ledger_api.identifier = EthereumApi.identifier + + try: + ledger_api.api.eth.default_account = crypto.address + except Exception as e: # pragma: nocover + raise click.ClickException(str(e)) + + return ledger_api, crypto + + def check_required_enviroment_variables( + self, configs: Tuple[ContractConfig, ...] + ) -> None: + """Check for required enviroment variables when working with the custom chain.""" + if self.chain_type != ChainType.CUSTOM: + return + missing = [] + for config in configs: + if config.contracts[self.chain_type] is None: + missing.append(config) + + if len(missing) == 0: + return + + error = "Addresses for following contracts are None, please set them using their respective environment variables\n" + for config in missing: + error += f"- Set `{config.name}` address using `CUSTOM_{config.name.upper()}_ADDRESS`\n" + raise click.ClickException(error[:-1]) + + +class MintHelper(OnChainHelper): # pylint: disable=too-many-instance-attributes + """Mint helper.""" + + package_path: Path + package_type: PackageType + package_configuration: PackageConfiguration + old_metadata: Dict[str, Any] + nft: NFTHashOrPath + dependencies: List[int] + agent_id: int + metadata_hash: str + metadata_string: str + token_id: Optional[int] + + def __init__( # pylint: disable=too-many-arguments + self, + chain_type: ChainType, + key: Optional[Path] = None, + password: Optional[str] = None, + hwi: bool = False, + update_token: Optional[int] = None, + timeout: Optional[float] = None, + retries: Optional[int] = None, + sleep: Optional[float] = None, + dry_run: bool = False, + ) -> None: + """Initialize object.""" + super().__init__( + chain_type, + key, + password, + hwi, + timeout=timeout, + retries=retries, + sleep=sleep, + dry_run=dry_run, ) - raise click.ClickException(error_message) - - return found - - -def mint_component( # pylint: disable=too-many-arguments, too-many-locals - package_path: Path, - package_type: PackageType, - key: Optional[Path], - chain_type: ChainType, - nft: Optional[NFTHashOrPath] = None, - owner: Optional[str] = None, - password: Optional[str] = None, - skip_hash_check: bool = False, - use_latest_dependencies: bool = False, - timeout: Optional[float] = None, - hwi: bool = False, -) -> None: - """Mint component.""" - - is_agent = package_type == PackageType.AGENT - - if key is None and not hwi: - raise click.ClickException( - "Please provide key path using `--key` or use `--hwi` if you want to use a hardware wallet" + self.update_token = update_token + self.manager = MintManager( + ledger_api=self.ledger_api, + crypto=self.crypto, + chain_type=chain_type, + timeout=timeout, + retries=retries, + sleep=sleep, + dry_run=self.dry_run, ) - ledger_api, crypto = get_ledger_and_crypto_objects( - chain_type=chain_type, - key=key, - password=password, - hwi=hwi, - ) + def load_package_configuration( + self, + package_path: Path, + package_type: PackageType, + ) -> "MintHelper": + """Load package configuration.""" + try: + self.package_path = package_path + self.package_type = package_type + self.package_configuration = load_configuration_object( + package_type=package_type, + directory=package_path, + package_type_config_class=PACKAGE_TYPE_TO_CONFIG_CLASS, + ) + return self + except FileNotFoundError as e: # pragma: nocover + raise click.ClickException( + f"Cannot find configuration file for {package_type}" + ) from e + + def load_metadata(self) -> "MintHelper": # pragma: nocover + """Load metadata when updating a mint.""" + if self.update_token is None: + return self + + if self.package_type == PackageType.SERVICE: + is_service = True + is_agent = False + contract_address = ContractConfigs.get( + SERVICE_REGISTRY_CONTRACT.name + ).contracts[self.chain_type] + self.check_required_enviroment_variables( + configs=(ContractConfigs.service_registry,) + ) + elif self.package_type == PackageType.AGENT: + is_service = False + is_agent = True + contract_address = ContractConfigs.get( + AGENT_REGISTRY_CONTRACT.name + ).contracts[self.chain_type] + self.check_required_enviroment_variables( + configs=(ContractConfigs.agent_registry,) + ) + else: + is_service = False + is_agent = False + contract_address = ContractConfigs.get( + COMPONENT_REGISTRY_CONTRACT.name + ).contracts[self.chain_type] + self.check_required_enviroment_variables( + configs=(ContractConfigs.component_registry,) + ) - try: - package_configuration = load_configuration_object( - package_type=package_type, - directory=package_path, - package_type_config_class=PACKAGE_TYPE_TO_CONFIG_CLASS, + self.old_metadata = resolve_component_id( + ledger_api=self.ledger_api, + contract_address=contract_address, + is_agent=is_agent, + is_service=is_service, + token_id=self.update_token, ) - except FileNotFoundError as e: # pragma: nocover - raise click.ClickException( - f"Cannot find configuration file for {package_type}" - ) from e - if chain_type == ChainType.LOCAL and nft is None: - nft = IPFSHash(DEFAULT_NFT_IMAGE_HASH) + return self - if chain_type != ChainType.LOCAL and nft is None: - raise click.ClickException( - f"Please provide hash for NFT image to mint component on `{chain_type.value}` chain" - ) + def verify_nft(self, nft: Optional[NFTHashOrPath] = None) -> "MintHelper": + """Verify NFT image.""" - dependencies = get_on_chain_dependencies( - dependencies=package_configuration.package_dependencies, - skip_hash_check=skip_hash_check, - use_latest_dependencies=use_latest_dependencies, - ) + # If new NFT hash is not provided, check previous mint for NFT hash + if self.update_token is not None and nft is None: + image_uri = self.old_metadata.get("image", None) + if image_uri is not None: + nft = IPFSHash(image_uri.replace("ipfs://", "")) - metadata_hash, metadata_string = publish_metadata( - package_id=package_configuration.package_id, - package_path=package_path, - nft=cast(str, nft), - description=package_configuration.description, - ) + # NFTs are required for minting components on a local chain deployement + if self.chain_type == ChainType.LOCAL and nft is None: + nft = IPFSHash(DEFAULT_NFT_IMAGE_HASH) - try: - token_id = _mint_component( - ledger_api=ledger_api, - crypto=crypto, - metadata_hash=metadata_hash, - owner=owner, - component_type=UnitType.AGENT if is_agent else UnitType.COMPONENT, - chain_type=chain_type, - dependencies=dependencies, - timeout=timeout, + if self.chain_type != ChainType.LOCAL and nft is None: + raise click.ClickException( + f"Please provide hash for NFT image to mint component on `{self.chain_type.value}` chain" + ) + + self.nft = nft + return self + + def verify_component_dependencies( + self, + dependencies: Tuple[str], + skip_dependencies_check: bool = False, + skip_hash_check: bool = False, + ) -> "MintHelper": + """Verify component dependencies.""" + self.dependencies = list(map(int, dependencies)) + if skip_dependencies_check: + return self + if self.chain_type != ChainType.ETHEREUM: + return self + try: + verify_component_dependencies( + ledger_api=self.ledger_api, + contract_address=ContractConfigs.get( + COMPONENT_REGISTRY_CONTRACT.name + ).contracts[self.chain_type], + dependencies=self.dependencies, + package_configuration=self.package_configuration, + skip_hash_check=skip_hash_check, + ) + return self + except (FailedToRetrieveComponentMetadata, DependencyError) as e: + raise click.ClickException(f"Dependency verification failed; {e}") from e + + def verify_service_dependencies( + self, + agent_id: int, + skip_dependencies_check: bool = False, + skip_hash_check: bool = False, + ) -> "MintHelper": + """Verify component dependencies.""" + self.agent_id = agent_id + if skip_dependencies_check: + return self + if self.chain_type != ChainType.ETHEREUM: + return self + try: + verify_service_dependencies( + ledger_api=self.ledger_api, + contract_address=ContractConfigs.get( + AGENT_REGISTRY_CONTRACT.name + ).contracts[self.chain_type], + agent_id=self.agent_id, + service_configuration=cast(Service, self.package_configuration), + skip_hash_check=skip_hash_check, + ) + return self + except FailedToRetrieveComponentMetadata as e: + raise click.ClickException(f"Dependency verification failed; {e}") from e + except DependencyError as e: + raise click.ClickException(f"Dependency verification failed; {e}") from e + + def publish_metadata(self) -> "MintHelper": + """Publish metadata.""" + self.metadata_hash, self.metadata_string = publish_metadata( + package_id=self.package_configuration.package_id, + package_path=self.package_path, + nft=cast(str, self.nft), + description=self.package_configuration.description, ) - except InvalidMintParameter as e: - raise click.ClickException(f"Invalid parameters provided; {e}") from e - except ComponentMintFailed as e: - raise click.ClickException( - f"Component mint failed with following error; {e}" - ) from e - except FailedToRetrieveTokenId as e: - raise click.ClickException( - f"Component mint was successful but token ID retrieving failed with following error; {e}" - ) from e - - click.echo("Component minted with:") - click.echo(f"\tPublic ID: {package_configuration.public_id}") - click.echo(f"\tMetadata Hash: {metadata_hash}") - if token_id is not None: - click.echo(f"\tToken ID: {token_id}") - (Path.cwd() / f"{token_id}.json").write_text(metadata_string) - else: - raise click.ClickException( - "Could not verify metadata hash to retrieve the token ID" + return self + + def mint_component( + self, + owner: Optional[str] = None, + component_type: UnitType = UnitType.COMPONENT, + ) -> None: + """Mint component.""" + + self.check_required_enviroment_variables( + configs=( + ContractConfigs.registries_manager, + ( + ContractConfigs.component_registry + if component_type == UnitType.COMPONENT + else ContractConfigs.agent_registry + ), + ) ) + try: + self.token_id = self.manager.mint_component( + metadata_hash=self.metadata_hash, + component_type=component_type, + owner=owner, + dependencies=self.dependencies, + ) + except ChainInteractionError as e: # pragma: nocover + raise click.ClickException( + f"Component mint failed with following error; {e.__class__.__name__}({e})" + ) from e + + if self.dry_run: # pragma: nocover + return + + click.echo("Component minted with:") + click.echo(f"\tPublic ID: {self.package_configuration.public_id}") + click.echo(f"\tMetadata Hash: {self.metadata_hash}") + if self.token_id is not None: + click.echo(f"\tToken ID: {self.token_id}") + (Path.cwd() / f"{self.token_id}.json").write_text(self.metadata_string) + else: + raise click.ClickException( + "Could not verify metadata hash to retrieve the token ID" + ) -def mint_service( # pylint: disable=too-many-arguments, too-many-locals - package_path: Path, - key: Optional[Path], - chain_type: ChainType, - agent_id: int, - number_of_slots: int, - cost_of_bond: int, - threshold: int, - nft: Optional[NFTHashOrPath] = None, - owner: Optional[str] = None, - password: Optional[str] = None, - skip_hash_check: bool = False, - use_latest_dependencies: bool = False, - timeout: Optional[float] = None, - hwi: bool = False, -) -> None: - """Mint service""" - - if key is None and not hwi: # pragma: nocover - raise click.ClickException( - "Please provide key path using `--key` or use `--hwi` if you want to use a hardware wallet" + def mint_agent( + self, + owner: Optional[str] = None, + ) -> None: + """Mint agent.""" + self.mint_component( + owner=owner, + component_type=UnitType.AGENT, ) - ledger_api, crypto = get_ledger_and_crypto_objects( - chain_type=chain_type, - key=key, - password=password, - hwi=hwi, - ) - try: - package_configuration = cast( - Service, - load_configuration_object( - package_type=PackageType.SERVICE, - directory=package_path, - package_type_config_class=PACKAGE_TYPE_TO_CONFIG_CLASS, - ), + def mint_service( + self, + number_of_slots: int, + cost_of_bond: int, + threshold: int, + token: Optional[str] = None, + owner: Optional[str] = None, + ) -> None: + """Mint service""" + + if ( + not is_service_manager_token_compatible_chain(ledger_api=self.ledger_api) + and token is not None + ): + raise click.ClickException( + "Cannot use custom token for bonding on L2 chains" + ) + + self.check_required_enviroment_variables( + configs=( + ContractConfigs.service_manager, + ContractConfigs.service_registry, + ) ) - except FileNotFoundError as e: # pragma: nocover - raise click.ClickException( - f"Cannot find configuration file for {PackageType.SERVICE}" - ) from e - if chain_type == ChainType.LOCAL and nft is None: - nft = IPFSHash(DEFAULT_NFT_IMAGE_HASH) + try: + token_id = self.manager.mint_service( + metadata_hash=self.metadata_hash, + agent_ids=[ + self.agent_id, + ], + number_of_slots_per_agent=[ + number_of_slots, + ], + cost_of_bond_per_agent=[ + cost_of_bond, + ], + threshold=threshold, + token=token, + owner=owner, + ) + except ChainInteractionError as e: # pragma: nocover + raise click.ClickException( + f"Component mint failed with following error; {e.__class__.__name__}({e})" + ) from e + + if self.dry_run: # pragma: nocover + return + + click.echo("Service minted with:") + click.echo(f"\tPublic ID: {self.package_configuration.public_id}") + click.echo(f"\tMetadata Hash: {self.metadata_hash}") + if token_id is not None: + click.echo(f"\tToken ID: {token_id}") + (Path.cwd() / f"{token_id}.json").write_text(self.metadata_string) + else: + raise click.ClickException( + "Could not verify metadata hash to retrieve the token ID" + ) - if chain_type != ChainType.LOCAL and nft is None: - raise click.ClickException( - f"Please provide hash for NFT image to mint component on `{chain_type.value}` chain" + def update_component(self, component_type: UnitType = UnitType.COMPONENT) -> None: + """Update component.""" + self.check_required_enviroment_variables( + configs=( + ContractConfigs.registries_manager, + ( + ContractConfigs.component_registry + if component_type == UnitType.COMPONENT + else ContractConfigs.agent_registry + ), + ) ) + try: + self.token_id = self.manager.update_component( + metadata_hash=self.metadata_hash, + unit_id=cast(int, self.update_token), + component_type=component_type, + ) + except ChainInteractionError as e: # pragma: nocover + raise click.ClickException( + f"Component update failed with following error; {e.__class__.__name__}({e})" + ) from e + + if self.dry_run: # pragma: nocover + return + + click.echo("Component hash updated:") + click.echo(f"\tPublic ID: {self.package_configuration.public_id}") + click.echo(f"\tMetadata Hash: {self.metadata_hash}") + if self.token_id is not None: + click.echo(f"\tToken ID: {self.token_id}") + (Path.cwd() / f"{self.token_id}.json").write_text(self.metadata_string) + else: + raise click.ClickException( + "Could not verify metadata hash to retrieve the token ID" + ) - agent_ids = get_on_chain_dependencies( - dependencies={ - PackageId(PackageType.AGENT, package_configuration.agent), - }, - skip_hash_check=skip_hash_check, - use_latest_dependencies=use_latest_dependencies, - ) + def update_agent(self) -> None: + """Update agent.""" + self.update_component(component_type=UnitType.AGENT) + + def update_service( + self, + number_of_slots: int, + cost_of_bond: int, + threshold: int, + token: Optional[str] = None, + ) -> None: + """Update service""" + + self.check_required_enviroment_variables( + configs=( + ContractConfigs.service_manager, + ContractConfigs.service_registry, + ) + ) - if agent_id not in agent_ids: - raise click.ClickException( - "Agent ID not found in the list of on-chain agent IDs related to agent defined in the service" - f"\n\tService ID: {package_configuration.public_id}" - f"\n\tAgent ID: {package_configuration.agent}" + *_, state, _ = get_service_info( + ledger_api=self.ledger_api, + chain_type=self.chain_type, + token_id=cast(int, self.update_token), ) - metadata_hash, metadata_string = publish_metadata( - package_id=package_configuration.package_id, - package_path=package_path, - nft=cast(str, nft), - description=package_configuration.description, - ) + if ServiceState(state) != ServiceState.PRE_REGISTRATION: + raise click.ClickException( + "Cannot update service hash, service needs to be in the pre-registration state" + ) - try: - token_id = _mint_service( - ledger_api=ledger_api, - crypto=crypto, - metadata_hash=metadata_hash, - chain_type=chain_type, - agent_ids=[ - agent_id, - ], - number_of_slots_per_agent=[ - number_of_slots, - ], - cost_of_bond_per_agent=[ - cost_of_bond, - ], - threshold=threshold, + try: + token_id = self.manager.update_service( + metadata_hash=self.metadata_hash, + service_id=cast(int, self.update_token), + agent_ids=[ + self.agent_id, + ], + number_of_slots_per_agent=[ + number_of_slots, + ], + cost_of_bond_per_agent=[ + cost_of_bond, + ], + threshold=threshold, + token=token, + ) + except ChainInteractionError as e: # pragma: nocover + raise click.ClickException( + f"Component mint failed with following error; {e.__class__.__name__}({e})" + ) from e + + if self.dry_run: # pragma: nocover + return + + click.echo("Service updated with:") + click.echo(f"\tPublic ID: {self.package_configuration.public_id}") + click.echo(f"\tMetadata Hash: {self.metadata_hash}") + if token_id is not None: + click.echo(f"\tToken ID: {token_id}") + (Path.cwd() / f"{token_id}.json").write_text(self.metadata_string) + else: + raise click.ClickException( + "Could not verify metadata hash to retrieve the token ID" + ) + + +class ServiceHelper(OnChainHelper): + """Service helper.""" + + token: Optional[str] + token_secured: bool + + def __init__( # pylint: disable=too-many-arguments + self, + service_id: int, + chain_type: ChainType, + key: Optional[Path] = None, + password: Optional[str] = None, + hwi: bool = False, + timeout: Optional[float] = None, + retries: Optional[int] = None, + sleep: Optional[float] = None, + dry_run: bool = False, + ) -> None: + """Initialize object.""" + self.service_id = service_id + super().__init__( + chain_type, + key, + password, + hwi, timeout=timeout, - owner=owner, + retries=retries, + sleep=sleep, + dry_run=dry_run, ) - except ComponentMintFailed as e: - raise click.ClickException( - f"Service mint failed with following error; {e}" - ) from e - except FailedToRetrieveTokenId as e: - raise click.ClickException( - f"Service mint was successful but token ID retrieving failed with following error; {e}" - ) from e - - click.echo("Service minted with:") - click.echo(f"\tPublic ID: {package_configuration.public_id}") - click.echo(f"\tMetadata Hash: {metadata_hash}") - if token_id is not None: - click.echo(f"\tToken ID: {token_id}") - (Path.cwd() / f"{token_id}.json").write_text(metadata_string) - else: - raise click.ClickException( - "Could not verify metadata hash to retrieve the token ID" + self.manager = ServiceManager( + ledger_api=self.ledger_api, + crypto=self.crypto, + chain_type=self.chain_type, + timeout=self.timeout, + retries=self.retries, + sleep=self.sleep, + dry_run=dry_run, ) + def check_is_service_token_secured( + self, + token: Optional[str] = None, + ) -> "ServiceHelper": + """Check if service""" + if not is_service_manager_token_compatible_chain(ledger_api=self.ledger_api): + self.token = token + self.token_secured = False + return self + + if self.chain_type == ChainType.CUSTOM: + self.check_required_enviroment_variables( + configs=(ContractConfigs.service_registry_token_utility,) + ) -def activate_service( # pylint: disable=too-many-arguments - service_id: int, - key: Path, - chain_type: ChainType, - password: Optional[str] = None, - timeout: Optional[float] = None, - hwi: bool = False, -) -> None: - """Activate on-chain service""" + self.token = token + self.token_secured = is_service_token_secured( + ledger_api=self.ledger_api, + chain_type=self.chain_type, + service_id=self.service_id, + ) + if self.token_secured and self.token is None: + raise click.ClickException( + "Service is token secured, please provice token address using `--token` flag" + ) + ContractConfigs.erc20.contracts[self.chain_type] = cast(str, self.token) + return self + + def approve_erc20_usage(self, amount: int, spender: str) -> "ServiceHelper": + """Approve ERC20 usage.""" + + try: + approve_erc20_usage( + ledger_api=self.ledger_api, + crypto=self.crypto, + chain_type=self.chain_type, + spender=spender, + amount=amount, + sender=self.crypto.address, + dry_run=self.dry_run, + timeout=self.timeout, + sleep=self.sleep, + retries=self.retries, + ) + except ChainInteractionError as e: # pragma: nocover + raise click.ClickException(f"Error getting approval : {e}") + return self + + def activate_service(self) -> None: + """Activate on-chain service""" + + if self.token_secured: + amount = get_token_deposit_amount( + self.ledger_api, + chain_type=self.chain_type, + service_id=self.service_id, + ) + spender = ContractConfigs.get( + name=SERVICE_REGISTRY_TOKEN_UTILITY_CONTRACT.name + ).contracts[self.chain_type] + self.approve_erc20_usage( + amount=amount, + spender=spender, + ) - if key is None and not hwi: # pragma: nocover - raise click.ClickException( - "Please provide key path using `--key` or use `--hwi` if you want to use a hardware wallet" + self.check_required_enviroment_variables( + configs=( + ContractConfigs.service_manager, + ContractConfigs.service_registry, + ) ) - ledger_api, crypto = get_ledger_and_crypto_objects( - chain_type=chain_type, - key=key, - password=password, - hwi=hwi, - ) + try: + self.manager.activate(service_id=self.service_id) + except ChainInteractionError as e: # pragma: nocover + raise click.ClickException( + f"Service activation failed with following error; {e.__class__.__name__}({e})" + ) from e + + if self.dry_run: # pragma: nocover + return + click.echo("Service activated succesfully") + + def register_instance(self, instances: List[str], agent_ids: List[int]) -> None: + """Register agents instances on an activated service""" + + if self.token_secured: + amount = get_activate_registration_amount( + ledger_api=self.ledger_api, + chain_type=self.chain_type, + service_id=self.service_id, + agents=agent_ids, + ) + spender = ContractConfigs.get( + name=SERVICE_REGISTRY_TOKEN_UTILITY_CONTRACT.name + ).contracts[self.chain_type] + self.approve_erc20_usage( + amount=amount, + spender=spender, + ) - try: - _activate_service( - ledger_api=ledger_api, - crypto=crypto, - chain_type=chain_type, - service_id=service_id, - timeout=timeout, - ) - except ServiceRegistrationFailed as e: - raise click.ClickException(str(e)) from e - - click.echo("Service activated succesfully") - - -def register_instance( # pylint: disable=too-many-arguments - service_id: int, - instances: List[str], - agent_ids: List[int], - key: Path, - chain_type: ChainType, - password: Optional[str] = None, - timeout: Optional[float] = None, - hwi: bool = False, -) -> None: - """Register agents instances on an activated service""" - - if key is None and not hwi: # pragma: nocover - raise click.ClickException( - "Please provide key path using `--key` or use `--hwi` if you want to use a hardware wallet" + self.check_required_enviroment_variables( + configs=( + ContractConfigs.service_manager, + ContractConfigs.service_registry, + ) ) - ledger_api, crypto = get_ledger_and_crypto_objects( - chain_type=chain_type, - key=key, - password=password, - hwi=hwi, - ) + try: + self.manager.register_instance( + service_id=self.service_id, + instances=instances, + agent_ids=agent_ids, + ) + except ChainInteractionError as e: # pragma: nocover + raise click.ClickException( + f"Service activation failed with following error; {e.__class__.__name__}({e})" + ) from e + + if self.dry_run: # pragma: nocover + return + click.echo("Agent instance registered succesfully") + + def deploy_service( + self, + reuse_multisig: bool = False, + fallback_handler: Optional[str] = None, + ) -> None: + """Deploy a service with registration activated""" + + self.check_required_enviroment_variables( + configs=( + ContractConfigs.service_manager, + ContractConfigs.service_registry, + ContractConfigs.gnosis_safe_proxy_factory, + ContractConfigs.gnosis_safe_same_address_multisig, + ContractConfigs.multisend, + ) + ) - try: - _register_instance( - ledger_api=ledger_api, - crypto=crypto, - chain_type=chain_type, - service_id=service_id, - instances=instances, - agent_ids=agent_ids, - timeout=timeout, + try: + self.manager.deploy( + service_id=self.service_id, + reuse_multisig=reuse_multisig, + fallback_handler=fallback_handler, + ) + except ChainInteractionError as e: # pragma: nocover + raise click.ClickException( + f"Service deployment failed with following error; {e.__class__.__name__}({e})" + ) from e + + if self.dry_run: # pragma: nocover + return + click.echo("Service deployed succesfully") + + def terminate_service(self) -> None: + """Terminate a service""" + + self.check_required_enviroment_variables( + configs=( + ContractConfigs.service_manager, + ContractConfigs.service_registry, + ) ) - except InstanceRegistrationFailed as e: - raise click.ClickException(str(e)) from e - - click.echo("Agent instance registered succesfully") - - -def deploy_service( # pylint: disable=too-many-arguments - service_id: int, - key: Path, - chain_type: ChainType, - deployment_payload: Optional[str] = None, - password: Optional[str] = None, - timeout: Optional[float] = None, - hwi: bool = False, -) -> None: - """Deploy a service with registration activated""" - - if key is None and not hwi: # pragma: nocover - raise click.ClickException( - "Please provide key path using `--key` or use `--hwi` if you want to use a hardware wallet" + + try: + self.manager.terminate(service_id=self.service_id) + except ChainInteractionError as e: # pragma: nocover + raise click.ClickException( + f"Service terminatation failed with following error; {e.__class__.__name__}({e})" + ) from e + click.echo("Service terminated succesfully") + + def unbond_service(self) -> None: + """Unbond a service""" + + self.check_required_enviroment_variables( + configs=( + ContractConfigs.service_manager, + ContractConfigs.service_registry, + ) ) - ledger_api, crypto = get_ledger_and_crypto_objects( + try: + self.manager.unbond(service_id=self.service_id) + except ChainInteractionError as e: # pragma: nocover + raise click.ClickException( + f"Service unbonding failed with following error; {e.__class__.__name__}({e})" + ) from e + click.echo("Service unbonded succesfully") + + +def print_service_info(service_id: int, chain_type: ChainType) -> None: + """Print service information""" + ledger_api, _ = OnChainHelper.get_ledger_and_crypto_objects(chain_type=chain_type) + ( + security_deposit, + multisig_address, + _, + threshold, + max_agents, + number_of_agent_instances, + _service_state, + cannonical_agents, + ) = get_service_info( + ledger_api=ledger_api, chain_type=chain_type, - key=key, - password=password, - hwi=hwi, + token_id=service_id, ) - - try: - _deploy_service( - ledger_api=ledger_api, - crypto=crypto, - chain_type=chain_type, - service_id=service_id, - deployment_payload=deployment_payload, - timeout=timeout, + service_state = ServiceState(_service_state) + rows = [ + ("Property", "Value"), + ("Service State", service_state.name), + ("Security Deposit", security_deposit), + ("Multisig Address", multisig_address), + ("Cannonical Agents", ", ".join(map(str, cannonical_agents))), + ("Max Agents", max_agents), + ("Threshold", threshold), + ("Number Of Agent Instances", number_of_agent_instances), + ] + + if service_state.value >= ServiceState.ACTIVE_REGISTRATION.value: + rows.append( + ( + "Registered Instances", + "\n".join( + map( + lambda x: f"- {x}", + get_agent_instances( + ledger_api=ledger_api, + chain_type=chain_type, + token_id=service_id, + ).get("agentInstances", []), + ), + ), + ), ) - except ServiceDeployFailed as e: - raise click.ClickException(str(e)) from e - - click.echo("Service deployed succesfully") + click.echo(Texttable().add_rows(rows=rows).draw()) diff --git a/autonomy/cli/helpers/deployment.py b/autonomy/cli/helpers/deployment.py index 15341bdc33..3566ce3a2c 100644 --- a/autonomy/cli/helpers/deployment.py +++ b/autonomy/cli/helpers/deployment.py @@ -19,6 +19,8 @@ """Deployment helpers.""" import os +import shutil +import time from pathlib import Path from typing import Dict, List, Optional, Tuple @@ -27,14 +29,14 @@ from aea.helpers.base import cd from compose.cli import main as docker_compose from compose.config.errors import ConfigurationError +from compose.project import Project, ProjectError from docker.errors import NotFound -from web3.exceptions import BadFunctionCallOutput from autonomy.chain.config import ChainType, ContractConfigs from autonomy.chain.exceptions import FailedToRetrieveComponentMetadata from autonomy.chain.service import get_agent_instances, get_service_info from autonomy.chain.utils import resolve_component_id -from autonomy.cli.helpers.chain import get_ledger_and_crypto_objects +from autonomy.cli.helpers.chain import OnChainHelper from autonomy.cli.helpers.registry import fetch_service_ipfs from autonomy.configurations.constants import DEFAULT_SERVICE_CONFIG_FILE from autonomy.configurations.loader import load_service_config @@ -73,16 +75,33 @@ def _build_dirs(build_dir: Path) -> None: click.echo( f"Updating permissions failed for {path}, please do it manually." ) + except AttributeError: # pragma: no cover + continue -def run_deployment( - build_dir: Path, no_recreate: bool = False, remove_orphans: bool = False -) -> None: - """Run deployment.""" +def _print_log(compose_app: docker_compose.TopLevelCommand) -> None: + """Print docker container logs.""" + terminal_width, _ = shutil.get_terminal_size() + for service in compose_app.project.service_names: + try: + click.echo("=" * terminal_width) + click.echo(f"Trying to get logs for {service}") + click.echo(compose_app.project.client.logs(service)) + except NotFound: + continue - click.echo(f"Running build @ {build_dir}") + +def _kill_containers(compose_app: docker_compose.TopLevelCommand) -> None: + """Kill active containers before exiting.""" + for container in compose_app.project.containers(compose_app.project.service_names): + click.echo(f"Trying to kill {container.name}") + container.kill() + + +def _load_compose_project(build_dir: Path) -> Project: + """Load docker compose project.""" try: - project = docker_compose.project_from_options(build_dir, {}) + return docker_compose.project_from_options(build_dir, {}) except ConfigurationError as e: # pragma: no cover if "Invalid interpolation format" in e.msg: raise click.ClickException( @@ -91,11 +110,21 @@ def run_deployment( ) raise + +def run_deployment( + build_dir: Path, + no_recreate: bool = False, + remove_orphans: bool = False, + detach: bool = False, +) -> None: + """Run deployment.""" + click.echo(f"Running build @ {build_dir}") try: + project = _load_compose_project(build_dir=build_dir) commands = docker_compose.TopLevelCommand(project=project) commands.up( { - "--detach": False, + "--detach": True, "--no-color": False, "--quiet-pull": False, "--no-deps": False, @@ -116,6 +145,31 @@ def run_deployment( "SERVICE": None, } ) + if detach: + click.echo("The service is running...") + return + click.echo("The service is running, press CTRL + C to stop...") + while True: + time.sleep(1) + except NotFound as e: # pragma: no cover + raise click.ClickException(e.explanation) + except ProjectError as e: # pragma: no cover + click.echo("Error occured bringing up the project") + _print_log(compose_app=commands) + _kill_containers(compose_app=commands) + raise click.ClickException(e) + except KeyboardInterrupt: # pragma: no cover + stop_deployment(build_dir=build_dir) + + +def stop_deployment(build_dir: Path) -> None: + """Stop running deployment.""" + try: + project = _load_compose_project(build_dir=build_dir) + commands = docker_compose.TopLevelCommand(project=project) + click.echo("\nDon't cancel while stopping services...") + commands.down({"--volumes": False, "--remove-orphans": True, "--rmi": None}) + _kill_containers(compose_app=commands) except NotFound as e: # pragma: no cover raise click.ClickException(e.explanation) @@ -126,7 +180,6 @@ def build_deployment( # pylint: disable=too-many-arguments, too-many-locals deployment_type: str, dev_mode: bool, number_of_agents: Optional[int] = None, - password: Optional[str] = None, packages_dir: Optional[Path] = None, open_aea_dir: Optional[Path] = None, open_autonomy_dir: Optional[Path] = None, @@ -159,7 +212,6 @@ def build_deployment( # pylint: disable=too-many-arguments, too-many-locals service_path=Path.cwd(), type_of_deployment=deployment_type, keys_file=keys_file, - private_keys_password=password, number_of_agents=number_of_agents, build_dir=build_dir, dev_mode=dev_mode, @@ -186,7 +238,7 @@ def _resolve_on_chain_token_id( ) -> Tuple[Dict[str, str], List[str], str, int]: """Resolve service metadata from tokenID""" - ledger_api, _ = get_ledger_and_crypto_objects(chain_type=chain_type) + ledger_api, _ = OnChainHelper.get_ledger_and_crypto_objects(chain_type=chain_type) contract_address = ContractConfigs.service_registry.contracts[chain_type] click.echo(f"Fetching service metadata using chain type {chain_type.value}") @@ -199,14 +251,20 @@ def _resolve_on_chain_token_id( ledger_api=ledger_api, chain_type=chain_type, token_id=token_id ) agent_instances = info["agentInstances"] - (_, multisig_address, _, consensus_threshold, *_,) = get_service_info( + ( + _, + multisig_address, + _, + consensus_threshold, + *_, + ) = get_service_info( ledger_api=ledger_api, chain_type=chain_type, token_id=token_id ) except FailedToRetrieveComponentMetadata as e: raise click.ClickException(str(e)) from e - except BadFunctionCallOutput as e: + except Exception as e: raise click.ClickException( - f"Cannot find the service registry deployment; Service contract address {contract_address}" + f"Cannot find the service registry deployment; Service contract address {contract_address}; Error: {e}" ) from e return metadata, agent_instances, multisig_address, consensus_threshold @@ -220,8 +278,8 @@ def build_and_deploy_from_token( # pylint: disable=too-many-arguments, too-many n: Optional[int], deployment_type: str, aev: bool = False, - password: Optional[str] = None, no_deploy: bool = False, + detach: bool = False, ) -> None: """Build and run deployment from tokenID.""" @@ -253,7 +311,6 @@ def build_and_deploy_from_token( # pylint: disable=too-many-arguments, too-many multisig_address=multisig_address, consensus_threshold=consensus_threshold, apply_environment_variables=aev, - password=password, ) if not skip_image: click.echo("Building required images.") @@ -265,4 +322,4 @@ def build_and_deploy_from_token( # pylint: disable=too-many-arguments, too-many return click.echo("Running deployment") - run_deployment(build_dir) + run_deployment(build_dir, detach=detach) diff --git a/autonomy/cli/helpers/env.py b/autonomy/cli/helpers/env.py new file mode 100644 index 0000000000..aca14d4b92 --- /dev/null +++ b/autonomy/cli/helpers/env.py @@ -0,0 +1,48 @@ +# -*- coding: utf-8 -*- +# ------------------------------------------------------------------------------ +# +# Copyright 2023 Valory AG +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# ------------------------------------------------------------------------------ + +"""Environment variable helpers.""" + + +import json +import os +from pathlib import Path +from typing import Dict + +from dotenv import load_dotenv + + +def load_json(file: Path, serialize: bool = False) -> None: + """Load json.""" + env_vars: Dict = json.load(file.open(mode="r", encoding="utf-8")) + if serialize: + for key, val in env_vars.items(): + if isinstance(val, str): + continue # pragma: nocover + env_vars[key] = json.dumps(val) + os.environ.update(env_vars) + + +def load_env_file(file: Path, serialize_json: bool = False) -> None: + """Load env file.""" + + if file.name.endswith(".json"): + load_json(file=file, serialize=serialize_json) + else: + load_dotenv(dotenv_path=file) diff --git a/autonomy/cli/helpers/fsm_spec.py b/autonomy/cli/helpers/fsm_spec.py index 2089bb22da..77dd9d13a5 100644 --- a/autonomy/cli/helpers/fsm_spec.py +++ b/autonomy/cli/helpers/fsm_spec.py @@ -130,8 +130,13 @@ def check_one( dfa_check = dfa_from_file != dfa_from_object if len(error_strings) > 0: - errors = "\n".join(error_strings) - raise DFASpecificationError(f"Event reference check failed with \n{errors}") + errors = "\n- ".join( + [ + f"Unreferenced events found in `{abci_app_class.__name__}`", + *error_strings, + ] + ) + raise DFASpecificationError(errors) if dfa_check: raise DFASpecificationError( diff --git a/autonomy/cli/helpers/image.py b/autonomy/cli/helpers/image.py new file mode 100644 index 0000000000..1397a0fc40 --- /dev/null +++ b/autonomy/cli/helpers/image.py @@ -0,0 +1,59 @@ +# -*- coding: utf-8 -*- +# ------------------------------------------------------------------------------ +# +# Copyright 2023 Valory AG +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# ------------------------------------------------------------------------------ + +"""Image helpers.""" + +from pathlib import Path +from typing import Optional, Tuple + +import click +from aea.configurations.data_types import Dependency, PublicId + +from autonomy.configurations.loader import load_service_config +from autonomy.deploy.image import build_image as _build_image + + +def build_image( # pylint: disable=too-many-arguments + agent: Optional[PublicId], + service_dir: Optional[Path], + pull: bool = False, + dev: bool = False, + version: Optional[str] = None, + image_author: Optional[str] = None, + extra_dependencies: Optional[Tuple[Dependency, ...]] = None, + dockerfile: Optional[Path] = None, +) -> None: + """Build agent/service image.""" + extra_dependencies = extra_dependencies or () + if agent is None: + service_dir = Path(service_dir or Path.cwd()).absolute() + service = load_service_config(service_dir) + agent = service.agent + extra_dependencies = (*extra_dependencies, *service.dependencies.values()) + + click.echo(f"Building image with agent: {agent}\n") + _build_image( + agent=agent, + pull=pull, + dev=dev, + version=version, + image_author=image_author, + extra_dependencies=extra_dependencies, + dockerfile=dockerfile, + ) diff --git a/autonomy/cli/helpers/registry.py b/autonomy/cli/helpers/registry.py index f93f220ca5..98fa5cf2c8 100644 --- a/autonomy/cli/helpers/registry.py +++ b/autonomy/cli/helpers/registry.py @@ -25,7 +25,7 @@ from distutils.dir_util import copy_tree # pylint: disable=deprecated-module from pathlib import Path from shutil import copytree -from typing import cast +from typing import Optional, cast import click from aea.cli.registry.settings import REGISTRY_LOCAL, REGISTRY_REMOTE, REMOTE_IPFS @@ -58,36 +58,50 @@ IS_IPFS_PLUGIN_INSTALLED = False -def fetch_service(ctx: Context, public_id: PublicId) -> Path: +def fetch_service( + ctx: Context, + public_id: PublicId, + alias: Optional[str] = None, +) -> Path: """Fetch service.""" if ctx.registry_type == REGISTRY_REMOTE: - return fetch_service_remote(public_id) + return fetch_service_remote(public_id, alias=alias) if ctx.registry_type == REGISTRY_LOCAL: - return fetch_service_local(ctx, public_id) - return fetch_service_mixed(ctx, public_id) + return fetch_service_local(ctx, public_id, alias=alias) + return fetch_service_mixed(ctx, public_id, alias=alias) -def fetch_service_mixed(ctx: Context, public_id: PublicId) -> Path: +def fetch_service_mixed( + ctx: Context, + public_id: PublicId, + alias: Optional[str] = None, +) -> Path: """Fetch service in mixed mode.""" try: - return fetch_service_local(ctx, public_id) + return fetch_service_local(ctx, public_id, alias=alias) except Exception as e: # pylint: disable=broad-except click.echo( f"Fetch from local registry failed (reason={str(e)}), trying remote registry..." ) - return fetch_service_remote(public_id) + return fetch_service_remote(public_id, alias=alias) -def fetch_service_remote(public_id: PublicId) -> Path: +def fetch_service_remote( + public_id: PublicId, + alias: Optional[str] = None, +) -> Path: """Fetch service in remote mode.""" if get_default_remote_registry() == REMOTE_IPFS: - return fetch_service_ipfs(public_id) + return fetch_service_ipfs(public_id, alias=alias) raise Exception("HTTP registry not supported.") # pragma: nocover -def fetch_service_ipfs(public_id: PublicId) -> Path: +def fetch_service_ipfs( + public_id: PublicId, + alias: Optional[str] = None, +) -> Path: """Fetch service from IPFS node.""" if not IS_IPFS_PLUGIN_INSTALLED: @@ -96,7 +110,7 @@ def fetch_service_ipfs(public_id: PublicId) -> Path: with tempfile.TemporaryDirectory() as temp_dir: ipfs_tool = IPFSTool(get_ipfs_node_multiaddr()) download_path = Path(ipfs_tool.download(public_id.hash, temp_dir)) - package_path = Path.cwd() / download_path.name + package_path = Path.cwd() / (alias or download_path.name) shutil.copytree(download_path, package_path) if not Path(package_path, DEFAULT_SERVICE_CONFIG_FILE).exists(): @@ -117,7 +131,11 @@ def fetch_service_ipfs(public_id: PublicId) -> Path: return package_path -def fetch_service_local(ctx: Context, public_id: PublicId) -> Path: +def fetch_service_local( + ctx: Context, + public_id: PublicId, + alias: Optional[str] = None, +) -> Path: """Fetch service from local directory.""" with reraise_as_click_exception(ValueError): @@ -127,7 +145,7 @@ def fetch_service_local(ctx: Context, public_id: PublicId) -> Path: registry_path, public_id.author, SERVICES, public_id.name ) - target_path = Path(ctx.cwd, public_id.name) + target_path = Path(ctx.cwd, alias or public_id.name) if target_path.exists(): raise click.ClickException( f'Item "{target_path.name}" already exists in target folder "{target_path.parent}".' diff --git a/autonomy/cli/mint.py b/autonomy/cli/mint.py index 04d66f2b26..455f4d873c 100644 --- a/autonomy/cli/mint.py +++ b/autonomy/cli/mint.py @@ -20,7 +20,7 @@ """Mint command group definitions.""" from pathlib import Path -from typing import Optional, Union, cast +from typing import Optional, Tuple, Union, cast import click from aea.cli.utils.context import Context @@ -29,7 +29,7 @@ from aea.helpers.base import IPFSHash from autonomy.chain.config import ChainType -from autonomy.cli.helpers.chain import mint_component, mint_service +from autonomy.cli.helpers.chain import MintHelper from autonomy.cli.utils.click_utils import ( NFTArgument, PathArgument, @@ -46,20 +46,40 @@ type=str, help="Password for key pair", ) +dependencies_decorator = click.option( + "-d", + "--dependencies", + type=str, + multiple=True, + help="Dependencies for the package", +) nft_decorator = click.option( "--nft", type=NFTArgument(), help="IPFS hash or path for the NFT image", ) timeout_flag = click.option( - "-t", "--timeout", type=float, help="Timeout for verifying emitted events" + "-t", + "--timeout", + type=float, + help="Timeout for on-chain interactions", +) +retries_flag = click.option( + "-r", + "--retries", + type=int, + help="Max retries for on-chain interactions", +) +sleep_flag = click.option( + "--sleep", + type=float, + help="Sleep period between retries", ) owner_flag = click.option( "--owner", type=str, help="Owner address for the component", ) - key_path_decorator = click.option( "--key", type=PathArgument(exists=True, file_okay=True, dir_okay=False), @@ -70,38 +90,59 @@ is_flag=True, help="Use hardware wallet for signing the transactions.", ) +update_flag = click.option( + "--update", + type=int, + help="Update an already minted component with given token ID", +) +token_flag = click.option( + "--token", + type=str, + help="Token to use for bonding.", +) +dry_run_flag = click.option( + "--dry-run", + is_flag=True, + help="Perform a dry run for the transaction.", +) @click.group("mint") @pass_ctx @chain_selection_flag() @timeout_flag +@retries_flag +@sleep_flag +@dry_run_flag @click.option( - "-s", "--skip-hash-check", is_flag=True, help="Skip hash check when verifying dependencies on chain", ) @click.option( - "-l", - "--latest-dependencies", - "use_latest_dependencies", + "--skip-dependencies-check", is_flag=True, - help="Use latest on-chain dependencies if there are multiple dependencies with same package ID", + help="Skip dependencies check.", ) def mint( # pylint: disable=too-many-arguments ctx: Context, chain_type: str, skip_hash_check: bool, - use_latest_dependencies: bool, + skip_dependencies_check: bool, timeout: float, + retries: int, + sleep: float, + dry_run: bool, ) -> None: """Mint component on-chain.""" ctx.config["chain_type"] = ChainType(chain_type) ctx.config["skip_hash_check"] = skip_hash_check - ctx.config["use_latest_dependencies"] = use_latest_dependencies + ctx.config["skip_dependencies_check"] = skip_dependencies_check ctx.config["timeout"] = timeout + ctx.config["retries"] = retries + ctx.config["sleep"] = sleep + ctx.config["dry_run"] = dry_run @mint.command() @@ -109,32 +150,51 @@ def mint( # pylint: disable=too-many-arguments @key_path_decorator @hwi_flag @password_decorator +@dependencies_decorator @nft_decorator @owner_flag +@update_flag @pass_ctx def protocol( # pylint: disable=too-many-arguments ctx: Context, package_path: Path, key: Path, password: Optional[str], + dependencies: Tuple[str], nft: Optional[Union[Path, IPFSHash]], owner: Optional[str], + update: Optional[int], hwi: bool = False, ) -> None: """Mint a protocol component.""" - mint_component( - package_path=package_path, - package_type=PackageType.PROTOCOL, - key=key, - chain_type=cast(ChainType, ctx.config.get("chain_type")), - password=password, - nft=nft, - owner=owner, - skip_hash_check=ctx.config.get("skip_hash_check", False), - timeout=ctx.config["timeout"], - hwi=hwi, + mint_helper = ( + MintHelper( + chain_type=cast(ChainType, ctx.config.get("chain_type")), + key=key, + password=password, + hwi=hwi, + update_token=update, + dry_run=ctx.config.get("dry_run"), + timeout=ctx.config.get("timeout"), + retries=ctx.config.get("retries"), + sleep=ctx.config.get("sleep"), + ) + .load_package_configuration( + package_path=package_path, package_type=PackageType.PROTOCOL + ) + .load_metadata() + .verify_nft(nft=nft) + .verify_component_dependencies( + dependencies=dependencies, + skip_hash_check=ctx.config.get("skip_hash_check", False), + skip_dependencies_check=ctx.config.get("skip_dependencies_check", False), + ) + .publish_metadata() ) + if update is not None: + return mint_helper.update_component() + return mint_helper.mint_component(owner=owner) @mint.command() @@ -142,32 +202,51 @@ def protocol( # pylint: disable=too-many-arguments @key_path_decorator @hwi_flag @password_decorator +@dependencies_decorator @nft_decorator @owner_flag +@update_flag @pass_ctx def contract( # pylint: disable=too-many-arguments ctx: Context, package_path: Path, key: Path, password: Optional[str], + dependencies: Tuple[str], nft: Optional[Union[Path, IPFSHash]], owner: Optional[str], + update: Optional[int], hwi: bool = False, ) -> None: """Mint a contract component.""" - mint_component( - package_path=package_path, - package_type=PackageType.CONTRACT, - key=key, - chain_type=cast(ChainType, ctx.config.get("chain_type")), - password=password, - nft=nft, - owner=owner, - skip_hash_check=ctx.config.get("skip_hash_check", False), - timeout=ctx.config["timeout"], - hwi=hwi, + mint_helper = ( + MintHelper( + chain_type=cast(ChainType, ctx.config.get("chain_type")), + key=key, + password=password, + hwi=hwi, + update_token=update, + dry_run=ctx.config.get("dry_run"), + timeout=ctx.config.get("timeout"), + retries=ctx.config.get("retries"), + sleep=ctx.config.get("sleep"), + ) + .load_package_configuration( + package_path=package_path, package_type=PackageType.CONTRACT + ) + .load_metadata() + .verify_nft(nft=nft) + .verify_component_dependencies( + dependencies=dependencies, + skip_hash_check=ctx.config.get("skip_hash_check", False), + skip_dependencies_check=ctx.config.get("skip_dependencies_check", False), + ) + .publish_metadata() ) + if update is not None: + return mint_helper.update_component() + return mint_helper.mint_component(owner=owner) @mint.command() @@ -175,32 +254,51 @@ def contract( # pylint: disable=too-many-arguments @key_path_decorator @hwi_flag @password_decorator +@dependencies_decorator @nft_decorator @owner_flag +@update_flag @pass_ctx def connection( # pylint: disable=too-many-arguments ctx: Context, package_path: Path, key: Path, password: Optional[str], + dependencies: Tuple[str], nft: Optional[Union[Path, IPFSHash]], owner: Optional[str], + update: Optional[int], hwi: bool = False, ) -> None: """Mint a connection component.""" - mint_component( - package_path=package_path, - package_type=PackageType.CONNECTION, - key=key, - chain_type=cast(ChainType, ctx.config.get("chain_type")), - password=password, - nft=nft, - owner=owner, - skip_hash_check=ctx.config.get("skip_hash_check", False), - timeout=ctx.config["timeout"], - hwi=hwi, + mint_helper = ( + MintHelper( + chain_type=cast(ChainType, ctx.config.get("chain_type")), + key=key, + password=password, + hwi=hwi, + update_token=update, + dry_run=ctx.config.get("dry_run"), + timeout=ctx.config.get("timeout"), + retries=ctx.config.get("retries"), + sleep=ctx.config.get("sleep"), + ) + .load_package_configuration( + package_path=package_path, package_type=PackageType.CONNECTION + ) + .load_metadata() + .verify_nft(nft=nft) + .verify_component_dependencies( + dependencies=dependencies, + skip_hash_check=ctx.config.get("skip_hash_check", False), + skip_dependencies_check=ctx.config.get("skip_dependencies_check", False), + ) + .publish_metadata() ) + if update is not None: + return mint_helper.update_component() + return mint_helper.mint_component(owner=owner) @mint.command() @@ -208,32 +306,51 @@ def connection( # pylint: disable=too-many-arguments @key_path_decorator @hwi_flag @password_decorator +@dependencies_decorator @nft_decorator @owner_flag +@update_flag @pass_ctx def skill( # pylint: disable=too-many-arguments ctx: Context, package_path: Path, key: Path, password: Optional[str], + dependencies: Tuple[str], nft: Optional[Union[Path, IPFSHash]], owner: Optional[str], + update: Optional[int], hwi: bool = False, ) -> None: """Mint a skill component.""" - mint_component( - package_path=package_path, - package_type=PackageType.SKILL, - key=key, - chain_type=cast(ChainType, ctx.config.get("chain_type")), - password=password, - nft=nft, - owner=owner, - skip_hash_check=ctx.config.get("skip_hash_check", False), - timeout=ctx.config["timeout"], - hwi=hwi, + mint_helper = ( + MintHelper( + chain_type=cast(ChainType, ctx.config.get("chain_type")), + key=key, + password=password, + hwi=hwi, + update_token=update, + dry_run=ctx.config.get("dry_run"), + timeout=ctx.config.get("timeout"), + retries=ctx.config.get("retries"), + sleep=ctx.config.get("sleep"), + ) + .load_package_configuration( + package_path=package_path, package_type=PackageType.SKILL + ) + .load_metadata() + .verify_nft(nft=nft) + .verify_component_dependencies( + dependencies=dependencies, + skip_hash_check=ctx.config.get("skip_hash_check", False), + skip_dependencies_check=ctx.config.get("skip_dependencies_check", False), + ) + .publish_metadata() ) + if update is not None: + return mint_helper.update_component() + return mint_helper.mint_component(owner=owner) @mint.command() @@ -241,32 +358,53 @@ def skill( # pylint: disable=too-many-arguments @key_path_decorator @hwi_flag @password_decorator +@dependencies_decorator @nft_decorator @owner_flag +@update_flag @pass_ctx def agent( # pylint: disable=too-many-arguments ctx: Context, package_path: Path, key: Path, password: Optional[str], + dependencies: Tuple[str], nft: Optional[Union[Path, IPFSHash]], owner: Optional[str], + update: Optional[int], hwi: bool = False, ) -> None: """Mint an agent.""" + if len(dependencies) == 0: + raise click.ClickException("Agent packages needs to have dependencies") - mint_component( - package_path=package_path, - package_type=PackageType.AGENT, - key=key, - chain_type=cast(ChainType, ctx.config.get("chain_type")), - password=password, - nft=nft, - owner=owner, - skip_hash_check=ctx.config.get("skip_hash_check", False), - timeout=ctx.config["timeout"], - hwi=hwi, + mint_helper = ( + MintHelper( + chain_type=cast(ChainType, ctx.config.get("chain_type")), + key=key, + password=password, + hwi=hwi, + update_token=update, + dry_run=ctx.config.get("dry_run"), + timeout=ctx.config.get("timeout"), + retries=ctx.config.get("retries"), + sleep=ctx.config.get("sleep"), + ) + .load_package_configuration( + package_path=package_path, package_type=PackageType.AGENT + ) + .load_metadata() + .verify_nft(nft=nft) + .verify_component_dependencies( + dependencies=dependencies, + skip_hash_check=ctx.config.get("skip_hash_check", False), + skip_dependencies_check=ctx.config.get("skip_dependencies_check", False), + ) + .publish_metadata() ) + if update is not None: + return mint_helper.update_agent() + return mint_helper.mint_agent(owner=owner) @mint.command() @@ -276,6 +414,8 @@ def agent( # pylint: disable=too-many-arguments @password_decorator @nft_decorator @owner_flag +@update_flag +@token_flag @pass_ctx @click.option( "-a", @@ -315,22 +455,47 @@ def service( # pylint: disable=too-many-arguments # pylint: disable=too-many-a password: Optional[str], nft: Optional[Union[Path, IPFSHash]], owner: Optional[str], + update: Optional[int], + token: Optional[str], hwi: bool = False, ) -> None: """Mint a service""" - mint_service( - package_path=package_path, - key=key, - agent_id=agent_id, + mint_helper = ( + MintHelper( + chain_type=cast(ChainType, ctx.config.get("chain_type")), + key=key, + password=password, + hwi=hwi, + update_token=update, + dry_run=ctx.config.get("dry_run"), + timeout=ctx.config.get("timeout"), + retries=ctx.config.get("retries"), + sleep=ctx.config.get("sleep"), + ) + .load_package_configuration( + package_path=package_path, package_type=PackageType.SERVICE + ) + .load_metadata() + .verify_nft(nft=nft) + .verify_service_dependencies( + agent_id=agent_id, + skip_hash_check=ctx.config.get("skip_hash_check", False), + skip_dependencies_check=ctx.config.get("skip_dependencies_check", False), + ) + .publish_metadata() + ) + if update is not None: + return mint_helper.update_service( + number_of_slots=number_of_slots, + cost_of_bond=cost_of_bond, + threshold=threshold, + token=token, + ) + return mint_helper.mint_service( number_of_slots=number_of_slots, cost_of_bond=cost_of_bond, threshold=threshold, - chain_type=cast(ChainType, ctx.config.get("chain_type")), - password=password, - nft=nft, + token=token, owner=owner, - skip_hash_check=ctx.config.get("skip_hash_check", False), - timeout=ctx.config["timeout"], - hwi=hwi, ) diff --git a/autonomy/cli/packages.py b/autonomy/cli/packages.py index 7bfbd83aa1..9e4201c0e5 100644 --- a/autonomy/cli/packages.py +++ b/autonomy/cli/packages.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- # ------------------------------------------------------------------------------ # -# Copyright 2022 Valory AG +# Copyright 2022-2023 Valory AG # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -25,7 +25,7 @@ from warnings import warn import click -from aea.cli.packages import package_manager +from aea.cli.packages import package_manager, package_type_selector_prompt from aea.cli.utils.click_utils import reraise_as_click_exception from aea.cli.utils.context import Context from aea.cli.utils.decorators import pass_ctx @@ -51,8 +51,13 @@ is_flag=True, help="Check that fingerprints in packages.json match the local packages", ) +@click.option( + "--skip-missing", + is_flag=True, + help="Skip packages missing from the `packages.json` file.", +) @pass_ctx -def lock_packages(ctx: Context, check: bool) -> None: +def lock_packages(ctx: Context, check: bool, skip_missing: bool) -> None: """Lock local packages.""" packages_dir = Path(ctx.registry_path) @@ -70,7 +75,10 @@ def lock_packages(ctx: Context, check: bool) -> None: sys.exit(return_code) click.echo("Updating hashes...") - get_package_manager(packages_dir).update_package_hashes().dump() + get_package_manager(packages_dir).update_package_hashes( + selector_prompt=package_type_selector_prompt, + skip_missing=skip_missing, + ).dump() click.echo("Done") diff --git a/autonomy/cli/service.py b/autonomy/cli/service.py index c8b728f2f6..0889ee7506 100644 --- a/autonomy/cli/service.py +++ b/autonomy/cli/service.py @@ -27,59 +27,85 @@ from aea.cli.utils.decorators import pass_ctx from autonomy.chain.config import ChainType -from autonomy.cli.helpers.chain import ( - activate_service, - deploy_service, - register_instance, -) +from autonomy.cli.helpers.chain import ServiceHelper, print_service_info from autonomy.cli.mint import ( + dry_run_flag, hwi_flag, key_path_decorator, password_decorator, + retries_flag, + sleep_flag, timeout_flag, + token_flag, ) from autonomy.cli.utils.click_utils import chain_selection_flag +service_id_flag = click.argument("service_id", type=int) + + @click.group("service") @pass_ctx -@chain_selection_flag() @timeout_flag -def service(ctx: Context, chain_type: str, timeout: float) -> None: +@retries_flag +@sleep_flag +@dry_run_flag +@chain_selection_flag() +def service( + ctx: Context, + chain_type: str, + timeout: float, + retries: int, + sleep: float, + dry_run: bool, +) -> None: """Manage on-chain services.""" ctx.config["chain_type"] = ChainType(chain_type) ctx.config["timeout"] = timeout + ctx.config["retries"] = retries + ctx.config["sleep"] = sleep + ctx.config["dry_run"] = dry_run -@service.command() +@service.command(name="activate") @pass_ctx -@click.argument("service_id", type=int) +@service_id_flag @key_path_decorator @hwi_flag +@token_flag @password_decorator -def activate( +def _activate( ctx: Context, service_id: int, key: Path, hwi: bool, + token: Optional[str], password: Optional[str], ) -> None: """Activate service.""" - - activate_service( + ServiceHelper( service_id=service_id, - key=key, - hwi=hwi, chain_type=ctx.config["chain_type"], + key=key, password=password, - timeout=ctx.config["timeout"], - ) + hwi=hwi, + dry_run=ctx.config.get("dry_run"), + timeout=ctx.config.get("timeout"), + retries=ctx.config.get("retries"), + sleep=ctx.config.get("sleep"), + ).check_is_service_token_secured( + token=token, + ).activate_service() -@service.command() +@service.command("register") @pass_ctx -@click.argument("service_id", type=int) +@service_id_flag +@key_path_decorator +@hwi_flag +@token_flag +@password_decorator @click.option( "-i", "--instance", @@ -98,59 +124,141 @@ def activate( multiple=True, help="Agent ID", ) -@key_path_decorator -@hwi_flag -@password_decorator -def register( # pylint: disable=too-many-arguments +def _register( # pylint: disable=too-many-arguments ctx: Context, service_id: int, instances: List[str], agent_ids: List[int], + token: Optional[str], key: Path, hwi: bool, password: Optional[str], ) -> None: """Register instances.""" - - register_instance( + ServiceHelper( service_id=service_id, - instances=instances, - agent_ids=agent_ids, - key=key, - hwi=hwi, chain_type=ctx.config["chain_type"], + key=key, password=password, - timeout=ctx.config["timeout"], + hwi=hwi, + dry_run=ctx.config.get("dry_run"), + timeout=ctx.config.get("timeout"), + retries=ctx.config.get("retries"), + sleep=ctx.config.get("sleep"), + ).check_is_service_token_secured( + token=token, + ).register_instance( + instances=instances, + agent_ids=agent_ids, ) -@service.command() -@pass_ctx -@click.argument("service_id", type=int) +@service.command("deploy") @click.option( - "-d", - "--deployment-payload", - type=int, - help="Deployment payload value", + "--reuse-multisig", + is_flag=True, + help="Reuse mutlisig from previous deployment.", ) +@pass_ctx +@service_id_flag @key_path_decorator @hwi_flag @password_decorator -def deploy( +@click.option( + "-f", + "--fallback-handler", + type=str, + help="Fallback handler address for the gnosis safe multisig", +) +def _deploy( # pylint: disable=too-many-arguments ctx: Context, service_id: int, key: Path, hwi: bool, + reuse_multisig: bool, password: Optional[str], - deployment_payload: Optional[str], + fallback_handler: Optional[str], ) -> None: - """Activate service.""" + """Deploy a service.""" + ServiceHelper( + service_id=service_id, + chain_type=ctx.config["chain_type"], + key=key, + password=password, + hwi=hwi, + dry_run=ctx.config.get("dry_run"), + timeout=ctx.config.get("timeout"), + retries=ctx.config.get("retries"), + sleep=ctx.config.get("sleep"), + ).deploy_service( + reuse_multisig=reuse_multisig, + fallback_handler=fallback_handler, + ) + - deploy_service( +@service.command(name="terminate") +@pass_ctx +@service_id_flag +@key_path_decorator +@hwi_flag +@password_decorator +def _terminate( + ctx: Context, + service_id: int, + key: Path, + hwi: bool, + password: Optional[str], +) -> None: + """Terminate a service.""" + ServiceHelper( service_id=service_id, + chain_type=ctx.config["chain_type"], key=key, + password=password, hwi=hwi, + dry_run=ctx.config.get("dry_run"), + timeout=ctx.config.get("timeout"), + retries=ctx.config.get("retries"), + sleep=ctx.config.get("sleep"), + ).terminate_service() + + +@service.command(name="unbond") +@pass_ctx +@service_id_flag +@key_path_decorator +@hwi_flag +@password_decorator +def _unbond( + ctx: Context, + service_id: int, + key: Path, + hwi: bool, + password: Optional[str], +) -> None: + """Unbond a service.""" + ServiceHelper( + service_id=service_id, chain_type=ctx.config["chain_type"], + key=key, password=password, - deployment_payload=deployment_payload, + hwi=hwi, + dry_run=ctx.config.get("dry_run"), + timeout=ctx.config.get("timeout"), + retries=ctx.config.get("retries"), + sleep=ctx.config.get("sleep"), + ).unbond_service() + + +@service.command(name="info") +@pass_ctx +@service_id_flag +def _info( + ctx: Context, + service_id: int, +) -> None: + """Print service information.""" + print_service_info( + service_id=service_id, + chain_type=ctx.config["chain_type"], ) diff --git a/autonomy/configurations/base.py b/autonomy/configurations/base.py index bfd1898c1c..10d5afeaeb 100644 --- a/autonomy/configurations/base.py +++ b/autonomy/configurations/base.py @@ -35,7 +35,12 @@ PACKAGE_TYPE_TO_CONFIG_CLASS as _PACKAGE_TYPE_TO_CONFIG_CLASS, ) from aea.configurations.base import PackageConfiguration, ProtocolConfig, SkillConfig -from aea.configurations.data_types import PackageType, PublicId +from aea.configurations.data_types import ( + Dependencies, + Dependency, + PackageType, + PublicId, +) from aea.exceptions import AEAValidationError from aea.helpers.base import SimpleIdOrStr from aea.helpers.env_vars import apply_env_variables, generate_env_vars_recursively @@ -55,6 +60,13 @@ } +def load_dependencies(dependencies: Dict) -> Dependencies: + """Load dependencies.""" + return { + name: Dependency.from_json({name: spec}) for name, spec in dependencies.items() + } + + class Service(PackageConfiguration): # pylint: disable=too-many-instance-attributes """Service package configuration.""" @@ -75,6 +87,7 @@ class Service(PackageConfiguration): # pylint: disable=too-many-instance-attrib "agent", "number_of_agents", "description", + "dependencies", "deployment_config", "_aea_version", "_aea_version_specifiers", @@ -97,6 +110,7 @@ def __init__( # pylint: disable=too-many-arguments build_entrypoint: Optional[str] = None, overrides: Optional[List] = None, deployment: Optional[Dict] = None, + dependencies: Optional[Dependencies] = None, ) -> None: """Initialise object.""" @@ -115,6 +129,7 @@ def __init__( # pylint: disable=too-many-arguments self.description = description self.number_of_agents = number_of_agents self.deployment_config = deployment or {} + self.dependencies = dependencies or {} self._overrides = [] if overrides is None else overrides @@ -203,7 +218,7 @@ def check_overrides_valid( ) if component_id in processed: raise AEAValidationError( - f"Overrides for component {component_id} are defined more than once" + f"Overrides for component {component_id} are defined more than once in the service `{self.public_id}`" ) if has_multiple_overrides: for idx in range(self.number_of_agents): diff --git a/autonomy/configurations/loader.py b/autonomy/configurations/loader.py index dedf34ae9e..1def8c6304 100644 --- a/autonomy/configurations/loader.py +++ b/autonomy/configurations/loader.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- # ------------------------------------------------------------------------------ # -# Copyright 2022 Valory AG +# Copyright 2022-2023 Valory AG # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -34,7 +34,7 @@ from aea.helpers.io import open_file from aea.helpers.yaml_utils import yaml_load_all -from autonomy.configurations.base import Service +from autonomy.configurations.base import Service, load_dependencies COMPONENT_CONFIGS: Dict = { @@ -74,10 +74,24 @@ def load_service_config( service_config = apply_env_variables( service_config, env_variables=os.environ.copy() ) + + if "dependencies" in service_config: + dependencies = load_dependencies( + dependencies=service_config.pop("dependencies") + ) + else: + dependencies = {} + warn( + "`dependencies` parameter not defined in the service", + FutureWarning, + stacklevel=2, + ) + print("WARNING: `dependencies` parameter not defined in the service") + Service.validate_config_data(service_config) service_config["license_"] = service_config.pop("license") - service = Service(**service_config) + service = Service(**service_config, dependencies=dependencies) service.overrides = overrides return service diff --git a/autonomy/configurations/schemas/service_schema.json b/autonomy/configurations/schemas/service_schema.json index 4e43aff262..89d432a29b 100644 --- a/autonomy/configurations/schemas/service_schema.json +++ b/autonomy/configurations/schemas/service_schema.json @@ -1,7 +1,7 @@ { "$schema": "http://json-schema.org/draft-04/schema#", "description": "Schema for the deployment configuration file.", - "additionalProperties": false, + "additionalProperties": true, "type": "object", "required": [ "name", diff --git a/autonomy/constants.py b/autonomy/constants.py index 375b4cfa90..3751df3323 100644 --- a/autonomy/constants.py +++ b/autonomy/constants.py @@ -58,4 +58,4 @@ ACN_IMAGE_NAME = os.environ.get("ACN_IMAGE_NAME", "valory/open-acn-node") DEFAULT_DOCKER_IMAGE_AUTHOR = "valory" OAR_IMAGE = "{image_author}/oar-{agent}:{version}" -ABSTRACT_ROUND_ABCI_SKILL_WITH_HASH = "valory/abstract_round_abci:0.1.0:bafybeigiolzp3i6b3wwuau3yv2h5udqape3i7of73mlm2d6ud22irlkbme" +ABSTRACT_ROUND_ABCI_SKILL_WITH_HASH = "valory/abstract_round_abci:0.1.0:bafybeicrzndcdbue34yxwwb4hmmdhgzw4owcdcdag3ifj6thpx5wie3dp4" diff --git a/autonomy/data/Dockerfiles/agent/Dockerfile b/autonomy/data/Dockerfiles/agent/Dockerfile index a3182722b1..7dcdbe1776 100644 --- a/autonomy/data/Dockerfiles/agent/Dockerfile +++ b/autonomy/data/Dockerfiles/agent/Dockerfile @@ -1,20 +1,17 @@ ARG AUTONOMY_IMAGE_VERSION="latest" ARG AUTONOMY_IMAGE_NAME="valory/open-autonomy" - FROM ${AUTONOMY_IMAGE_NAME}:${AUTONOMY_IMAGE_VERSION} ARG AEA_AGENT ARG AUTHOR +ARG EXTRA_DEPENDENCIES -COPY start.sh /home/ubuntu -COPY install.sh /home/ubuntu +RUN aea init --reset --remote --ipfs --author ${AUTHOR} -VOLUME /home/ubuntu/logs -WORKDIR /home/ubuntu +WORKDIR /root -RUN aea init --reset --remote --ipfs --author ${AUTHOR} -RUN AEA_AGENT=${AEA_AGENT} bash install.sh +RUN AEA_AGENT=${AEA_AGENT} EXTRA_DEPENDENCIES=${EXTRA_DEPENDENCIES} bash /root/scripts/install.sh -CMD ["start.sh"] +CMD ["/root/scripts/start.sh"] HEALTHCHECK --interval=3s --timeout=600s --retries=600 CMD netstat -ltn | grep -c 26658 > /dev/null; if [ 0 != $? ]; then exit 1; fi; diff --git a/autonomy/data/Dockerfiles/agent/install.sh b/autonomy/data/Dockerfiles/agent/install.sh deleted file mode 100644 index c8bdb542d3..0000000000 --- a/autonomy/data/Dockerfiles/agent/install.sh +++ /dev/null @@ -1,17 +0,0 @@ -#! /bin/bash - -if [ "$AEA_AGENT" == "" ]; -then - echo "No Application specified!" - exit 1 -fi - -echo Running the aea with $(aea --version) - -echo "Loading $AEA_AGENT" -aea fetch $AEA_AGENT --alias agent || exit 1 -cd agent - -echo "Installing the necessary dependencies!" -aea install || exit 1 -cd .. \ No newline at end of file diff --git a/autonomy/data/Dockerfiles/agent/start.sh b/autonomy/data/Dockerfiles/agent/start.sh deleted file mode 100755 index 1172808701..0000000000 --- a/autonomy/data/Dockerfiles/agent/start.sh +++ /dev/null @@ -1,63 +0,0 @@ -#! /bin/bash - -# Debug mode -if [ "$DEBUG" == "1" ]; -then - echo "Debugging..." - while true; do echo "waiting" ; sleep 2; done -fi - -cd agent - -echo Running the aea with $(aea --version) -export FILE=/agent_key/ethereum_private_key.txt - -if [ -f "$FILE" ]; then - echo "AEA key provided. Copying to agent." - cp $FILE . -else - echo "No AEA key provided. Creating fresh." - if [ "$AEA_PASSWORD" != "" ]; - then - echo "Generating the fresh key with a password!" - aea generate-key ethereum --password $AEA_PASSWORD - else - echo "Generating the fresh key without a password!" - aea generate-key ethereum - fi - - if grep "open-aea-ledger-ethereum-flashbots" aea-config.yaml -q - then - cp ethereum_private_key.txt ethereum_flashbots_private_key.txt - fi - -fi - -if [ "$AEA_PASSWORD" != "" ]; -then - echo "Running the aea with a password!" - aea generate-key cosmos --connection --password $AEA_PASSWORD - aea add-key cosmos --connection --password $AEA_PASSWORD || (echo "Failed to generate the cosmos key needed for libp2p connection" && exit 1) - aea add-key ethereum --password $AEA_PASSWORD - - if grep "open-aea-ledger-ethereum-flashbots" aea-config.yaml -q - then - aea add-key ethereum_flashbots --password $AEA_PASSWORD - fi - - aea issue-certificates --password $AEA_PASSWORD --aev || (echo "Failed to add cosmos key needed for libp2p connection" && exit 1) - aea run --aev --password $AEA_PASSWORD -else - echo "Running the aea without a password!" - aea generate-key cosmos --connection - aea add-key cosmos --connection || (echo "Failed to generate the cosmos key needed for libp2p connection" && exit 1) - aea add-key ethereum - - if grep "open-aea-ledger-ethereum-flashbots" aea-config.yaml -q - then - aea add-key ethereum_flashbots - fi - - aea issue-certificates --aev || (echo "Failed to add cosmos key needed for libp2p connection" && exit 1) - aea run --aev -fi diff --git a/autonomy/data/Dockerfiles/dev/Dockerfile b/autonomy/data/Dockerfiles/dev/Dockerfile index a816686132..cf3898f484 100644 --- a/autonomy/data/Dockerfiles/dev/Dockerfile +++ b/autonomy/data/Dockerfiles/dev/Dockerfile @@ -1,27 +1,21 @@ ARG AEA_VERSION=latest -FROM valory/open-aea-user:${AEA_VERSION} -ARG AUTHOR=default_author -WORKDIR /home/ubuntu -ENV PATH=$PATH:/home/ubuntu/.local/bin +FROM valory/open-aea-user:${AEA_VERSION} -RUN sudo apt-get update && sudo apt-get upgrade -y -RUN cd /usr/bin && sudo rm python3 && sudo ln -s python3.10 python3 && sudo ln -s python3.10 python -RUN sudo apt-get install wait-for-it net-tools -y -RUN sudo apt remove --purge python3-virtualenv +ARG AUTHOR=default_author +RUN apt remove --purge python3-virtualenv +RUN python -m pip uninstall -y setuptools RUN python -m pip install --upgrade pip RUN python -m pip install --force-reinstall pipenv virtualenv --user -RUN python -m pip uninstall -y setuptools -WORKDIR /home/ubuntu -COPY openssl.cnf /etc/ssl -COPY Pipfile /home/ubuntu/Pipfile -COPY start_dev.sh /home/ubuntu/start_dev.sh -COPY start.sh /home/ubuntu/start.sh -COPY watcher.py /home/ubuntu/watcher.py +WORKDIR /root -CMD ["./start_dev.sh"] +COPY Pipfile /root/Pipfile +COPY start_dev.sh /root/start_dev.sh +COPY start.sh /root/start.sh +COPY watcher.py /root/watcher.py -HEALTHCHECK --interval=3s --timeout=600s --retries=600 CMD netstat -ltn | grep -c 26658 > /dev/null; if [ 0 != $? ]; then exit 1; fi; +CMD ["/root/start_dev.sh"] +HEALTHCHECK --interval=3s --timeout=600s --retries=600 CMD netstat -ltn | grep -c 26658 > /dev/null; if [ 0 != $? ]; then exit 1; fi; diff --git a/autonomy/data/Dockerfiles/dev/Pipfile b/autonomy/data/Dockerfiles/dev/Pipfile index 3c8172ea34..b1a1cb9ff3 100644 --- a/autonomy/data/Dockerfiles/dev/Pipfile +++ b/autonomy/data/Dockerfiles/dev/Pipfile @@ -10,7 +10,7 @@ requests = {version = "==2.27.1"} [dev-packages] asn1crypto = {version = "==1.4.0"} -cosmpy = {version = "==0.3.1"} +open-aea-cosmpy = {version = "==0.6.7"} open-aea = {editable = true, extras=["all"], path = "/open-aea"} open-aea-cli-ipfs = {editable = true, path = "/open-aea/plugins/aea-cli-ipfs"} open-aea-ledger-cosmos = {editable = true, path = "/open-aea/plugins/aea-ledger-cosmos"} diff --git a/autonomy/data/Dockerfiles/dev/openssl.cnf b/autonomy/data/Dockerfiles/dev/openssl.cnf deleted file mode 100644 index acbe687d89..0000000000 --- a/autonomy/data/Dockerfiles/dev/openssl.cnf +++ /dev/null @@ -1,365 +0,0 @@ -# -# OpenSSL example configuration file. -# This is mostly being used for generation of certificate requests. -# - -# Note that you can include other files from the main configuration -# file using the .include directive. -#.include filename - -# This definition stops the following lines choking if HOME isn't -# defined. -HOME = . - -openssl_conf = openssl_init - -[openssl_init] -providers = provider_sect - -[provider_sect] -default = default_sect -legacy = legacy_sect - -[default_sect] -activate = 1 - -[legacy_sect] -activate = 1 - -# Extra OBJECT IDENTIFIER info: -#oid_file = $ENV::HOME/.oid -oid_section = new_oids - -# To use this configuration file with the "-extfile" option of the -# "openssl x509" utility, name here the section containing the -# X.509v3 extensions to use: -# extensions = -# (Alternatively, use a configuration file that has only -# X.509v3 extensions in its main [= default] section.) - -[ new_oids ] - -# We can add new OIDs in here for use by 'ca', 'req' and 'ts'. -# Add a simple OID like this: -# testoid1=1.2.3.4 -# Or use config file substitution like this: -# testoid2=${testoid1}.5.6 - -# Policies used by the TSA examples. -tsa_policy1 = 1.2.3.4.1 -tsa_policy2 = 1.2.3.4.5.6 -tsa_policy3 = 1.2.3.4.5.7 - -#################################################################### -[ ca ] -default_ca = CA_default # The default ca section - -#################################################################### -[ CA_default ] - -dir = ./demoCA # Where everything is kept -certs = $dir/certs # Where the issued certs are kept -crl_dir = $dir/crl # Where the issued crl are kept -database = $dir/index.txt # database index file. -#unique_subject = no # Set to 'no' to allow creation of - # several certs with same subject. -new_certs_dir = $dir/newcerts # default place for new certs. - -certificate = $dir/cacert.pem # The CA certificate -serial = $dir/serial # The current serial number -crlnumber = $dir/crlnumber # the current crl number - # must be commented out to leave a V1 CRL -crl = $dir/crl.pem # The current CRL -private_key = $dir/private/cakey.pem# The private key - -x509_extensions = usr_cert # The extensions to add to the cert - -# Comment out the following two lines for the "traditional" -# (and highly broken) format. -name_opt = ca_default # Subject Name options -cert_opt = ca_default # Certificate field options - -# Extension copying option: use with caution. -# copy_extensions = copy - -# Extensions to add to a CRL. Note: Netscape communicator chokes on V2 CRLs -# so this is commented out by default to leave a V1 CRL. -# crlnumber must also be commented out to leave a V1 CRL. -# crl_extensions = crl_ext - -default_days = 365 # how long to certify for -default_crl_days= 30 # how long before next CRL -default_md = default # use public key default MD -preserve = no # keep passed DN ordering - -# A few difference way of specifying how similar the request should look -# For type CA, the listed attributes must be the same, and the optional -# and supplied fields are just that :-) -policy = policy_match - -# For the CA policy -[ policy_match ] -countryName = match -stateOrProvinceName = match -organizationName = match -organizationalUnitName = optional -commonName = supplied -emailAddress = optional - -# For the 'anything' policy -# At this point in time, you must list all acceptable 'object' -# types. -[ policy_anything ] -countryName = optional -stateOrProvinceName = optional -localityName = optional -organizationName = optional -organizationalUnitName = optional -commonName = supplied -emailAddress = optional - -#################################################################### -[ req ] -default_bits = 2048 -default_keyfile = privkey.pem -distinguished_name = req_distinguished_name -attributes = req_attributes -x509_extensions = v3_ca # The extensions to add to the self signed cert - -# Passwords for private keys if not present they will be prompted for -# input_password = secret -# output_password = secret - -# This sets a mask for permitted string types. There are several options. -# default: PrintableString, T61String, BMPString. -# pkix : PrintableString, BMPString (PKIX recommendation before 2004) -# utf8only: only UTF8Strings (PKIX recommendation after 2004). -# nombstr : PrintableString, T61String (no BMPStrings or UTF8Strings). -# MASK:XXXX a literal mask value. -# WARNING: ancient versions of Netscape crash on BMPStrings or UTF8Strings. -string_mask = utf8only - -# req_extensions = v3_req # The extensions to add to a certificate request - -[ req_distinguished_name ] -countryName = Country Name (2 letter code) -countryName_default = AU -countryName_min = 2 -countryName_max = 2 - -stateOrProvinceName = State or Province Name (full name) -stateOrProvinceName_default = Some-State - -localityName = Locality Name (eg, city) - -0.organizationName = Organization Name (eg, company) -0.organizationName_default = Internet Widgits Pty Ltd - -# we can do this but it is not needed normally :-) -#1.organizationName = Second Organization Name (eg, company) -#1.organizationName_default = World Wide Web Pty Ltd - -organizationalUnitName = Organizational Unit Name (eg, section) -#organizationalUnitName_default = - -commonName = Common Name (e.g. server FQDN or YOUR name) -commonName_max = 64 - -emailAddress = Email Address -emailAddress_max = 64 - -# SET-ex3 = SET extension number 3 - -[ req_attributes ] -challengePassword = A challenge password -challengePassword_min = 4 -challengePassword_max = 20 - -unstructuredName = An optional company name - -[ usr_cert ] - -# These extensions are added when 'ca' signs a request. - -# This goes against PKIX guidelines but some CAs do it and some software -# requires this to avoid interpreting an end user certificate as a CA. - -basicConstraints=CA:FALSE - -# Here are some examples of the usage of nsCertType. If it is omitted -# the certificate can be used for anything *except* object signing. - -# This is OK for an SSL server. -# nsCertType = server - -# For an object signing certificate this would be used. -# nsCertType = objsign - -# For normal client use this is typical -# nsCertType = client, email - -# and for everything including object signing: -# nsCertType = client, email, objsign - -# This is typical in keyUsage for a client certificate. -# keyUsage = nonRepudiation, digitalSignature, keyEncipherment - -# This will be displayed in Netscape's comment listbox. -nsComment = "OpenSSL Generated Certificate" - -# PKIX recommendations harmless if included in all certificates. -subjectKeyIdentifier=hash -authorityKeyIdentifier=keyid,issuer - -# This stuff is for subjectAltName and issuerAltname. -# Import the email address. -# subjectAltName=email:copy -# An alternative to produce certificates that aren't -# deprecated according to PKIX. -# subjectAltName=email:move - -# Copy subject details -# issuerAltName=issuer:copy - -#nsCaRevocationUrl = http://www.domain.dom/ca-crl.pem -#nsBaseUrl -#nsRevocationUrl -#nsRenewalUrl -#nsCaPolicyUrl -#nsSslServerName - -# This is required for TSA certificates. -# extendedKeyUsage = critical,timeStamping - -[ v3_req ] - -# Extensions to add to a certificate request - -basicConstraints = CA:FALSE -keyUsage = nonRepudiation, digitalSignature, keyEncipherment - -[ v3_ca ] - - -# Extensions for a typical CA - - -# PKIX recommendation. - -subjectKeyIdentifier=hash - -authorityKeyIdentifier=keyid:always,issuer - -basicConstraints = critical,CA:true - -# Key usage: this is typical for a CA certificate. However since it will -# prevent it being used as an test self-signed certificate it is best -# left out by default. -# keyUsage = cRLSign, keyCertSign - -# Some might want this also -# nsCertType = sslCA, emailCA - -# Include email address in subject alt name: another PKIX recommendation -# subjectAltName=email:copy -# Copy issuer details -# issuerAltName=issuer:copy - -# DER hex encoding of an extension: beware experts only! -# obj=DER:02:03 -# Where 'obj' is a standard or added object -# You can even override a supported extension: -# basicConstraints= critical, DER:30:03:01:01:FF - -[ crl_ext ] - -# CRL extensions. -# Only issuerAltName and authorityKeyIdentifier make any sense in a CRL. - -# issuerAltName=issuer:copy -authorityKeyIdentifier=keyid:always - -[ proxy_cert_ext ] -# These extensions should be added when creating a proxy certificate - -# This goes against PKIX guidelines but some CAs do it and some software -# requires this to avoid interpreting an end user certificate as a CA. - -basicConstraints=CA:FALSE - -# Here are some examples of the usage of nsCertType. If it is omitted -# the certificate can be used for anything *except* object signing. - -# This is OK for an SSL server. -# nsCertType = server - -# For an object signing certificate this would be used. -# nsCertType = objsign - -# For normal client use this is typical -# nsCertType = client, email - -# and for everything including object signing: -# nsCertType = client, email, objsign - -# This is typical in keyUsage for a client certificate. -# keyUsage = nonRepudiation, digitalSignature, keyEncipherment - -# This will be displayed in Netscape's comment listbox. -nsComment = "OpenSSL Generated Certificate" - -# PKIX recommendations harmless if included in all certificates. -subjectKeyIdentifier=hash -authorityKeyIdentifier=keyid,issuer - -# This stuff is for subjectAltName and issuerAltname. -# Import the email address. -# subjectAltName=email:copy -# An alternative to produce certificates that aren't -# deprecated according to PKIX. -# subjectAltName=email:move - -# Copy subject details -# issuerAltName=issuer:copy - -#nsCaRevocationUrl = http://www.domain.dom/ca-crl.pem -#nsBaseUrl -#nsRevocationUrl -#nsRenewalUrl -#nsCaPolicyUrl -#nsSslServerName - -# This really needs to be in place for it to be a proxy certificate. -proxyCertInfo=critical,language:id-ppl-anyLanguage,pathlen:3,policy:foo - -#################################################################### -[ tsa ] - -default_tsa = tsa_config1 # the default TSA section - -[ tsa_config1 ] - -# These are used by the TSA reply generation only. -dir = ./demoCA # TSA root directory -serial = $dir/tsaserial # The current serial number (mandatory) -crypto_device = builtin # OpenSSL engine to use for signing -signer_cert = $dir/tsacert.pem # The TSA signing certificate - # (optional) -certs = $dir/cacert.pem # Certificate chain to include in reply - # (optional) -signer_key = $dir/private/tsakey.pem # The TSA private key (optional) -signer_digest = sha256 # Signing digest to use. (Optional) -default_policy = tsa_policy1 # Policy if request did not specify it - # (optional) -other_policies = tsa_policy2, tsa_policy3 # acceptable policies (optional) -digests = sha1, sha256, sha384, sha512 # Acceptable message digests (mandatory) -accuracy = secs:1, millisecs:500, microsecs:100 # (optional) -clock_precision_digits = 0 # number of digits after dot. (optional) -ordering = yes # Is ordering defined for timestamps? - # (optional, default: no) -tsa_name = yes # Must the TSA name be included in the reply? - # (optional, default: no) -ess_cert_id_chain = no # Must the ESS cert id chain be included? - # (optional, default: no) -ess_cert_id_alg = sha1 # algorithm to compute certificate - # identifier (optional, default: sha1) diff --git a/autonomy/deploy/base.py b/autonomy/deploy/base.py index d75bbe7a1a..3b88aea0de 100644 --- a/autonomy/deploy/base.py +++ b/autonomy/deploy/base.py @@ -46,6 +46,7 @@ INFO, KEY_SCHEMA_ADDRESS, KEY_SCHEMA_PRIVATE_KEY, + KEY_SCHEMA_TYPE, ) @@ -53,6 +54,8 @@ ENV_VAR_AEA_AGENT = "AEA_AGENT" ENV_VAR_LOG_LEVEL = "LOG_LEVEL" ENV_VAR_AEA_PASSWORD = "AEA_PASSWORD" # nosec +ENV_VAR_DEPENDENCIES = "DEPENDENCIES" # nosec +ENV_VAR_OPEN_AUTONOMY_TM_WRITE_TO_LOG = "OPEN_AUTONOMY_TM_WRITE_TO_LOG" PARAM_ARGS_PATH = ("models", "params", "args") SETUP_PARAM_PATH = (*PARAM_ARGS_PATH, "setup") @@ -62,7 +65,7 @@ DEFAULT_ABCI_PORT = 26658 -ABCI_HOST_TEMPLATE = "abci{}" + KUBERNETES_DEPLOYMENT = "kubernetes" DOCKER_COMPOSE_DEPLOYMENT = "docker-compose" @@ -70,8 +73,8 @@ LOCALHOST = "localhost" TENDERMINT_P2P_PORT = 26656 -TENDERMINT_NODE = "http://node{}:26657" -TENDERMINT_COM = "http://node{}:8080" +TENDERMINT_NODE = "http://{host}:26657" +TENDERMINT_COM = "http://{host}:8080" TENDERMINT_NODE_LOCAL = f"http://{LOCALHOST}:26657" TENDERMINT_COM_LOCAL = f"http://{LOCALHOST}:8080" @@ -79,7 +82,7 @@ TENDERMINT_URL_PARAM = "tendermint_url" TENDERMINT_COM_URL_PARAM = "tendermint_com_url" -TENDERMINT_P2P_URL = "node{}:{}" +TENDERMINT_P2P_URL = "{host}:{port}" TENDERMINT_P2P_URL_PARAM = "tendermint_p2p_url" TENDERMINT_P2P_URL_ENV_VAR = "TM_P2P_NODE_URL_{}" @@ -94,11 +97,16 @@ } +def tm_write_to_log() -> bool: + """Check the environment variable to see if the user wants to write to log file or not.""" + return os.getenv(ENV_VAR_OPEN_AUTONOMY_TM_WRITE_TO_LOG, "true").lower() == "true" + + class NotValidKeysFile(Exception): """Raise when provided keys file is not valid.""" -class ServiceBuilder: +class ServiceBuilder: # pylint: disable=too-many-instance-attributes """Class to assist with generating deployments.""" deplopyment_type: str = DOCKER_COMPOSE_DEPLOYMENT @@ -108,7 +116,6 @@ def __init__( # pylint: disable=too-many-arguments self, service: Service, keys: Optional[List[Dict[str, str]]] = None, - private_keys_password: Optional[str] = None, agent_instances: Optional[List[str]] = None, apply_environment_variables: bool = False, ) -> None: @@ -123,11 +130,19 @@ def __init__( # pylint: disable=too-many-arguments self.service = service + self._service_name_clean = self.service.name.replace("_", "") self._keys = keys or [] self._agent_instances = agent_instances - self._private_keys_password = private_keys_password self._all_participants = self.try_get_all_participants() + def get_abci_container_name(self, index: int) -> str: + """Format ABCI container name.""" + return f"{self._service_name_clean}_abci_{index}" + + def get_tm_container_name(self, index: int) -> str: + """Format tendermint container name.""" + return f"{self._service_name_clean}_tm_{index}" + def try_get_all_participants(self) -> Optional[List[str]]: """Try get all participants from the ABCI overrides""" try: @@ -158,18 +173,6 @@ def try_get_all_participants(self) -> Optional[List[str]]: return None - @property - def private_keys_password( - self, - ) -> Optional[str]: - """Service password for agent keys.""" - - password = self._private_keys_password - if password is None: - password = os.environ.get("AUTONOLAS_SERVICE_PASSWORD") - - return password - @property def agent_instances( self, @@ -203,7 +206,6 @@ def from_dir( # pylint: disable=too-many-arguments path: Path, keys_file: Optional[Path] = None, number_of_agents: Optional[int] = None, - private_keys_password: Optional[str] = None, agent_instances: Optional[List[str]] = None, apply_environment_variables: bool = False, ) -> "ServiceBuilder": @@ -217,7 +219,6 @@ def from_dir( # pylint: disable=too-many-arguments service_builder = cls( service=service, apply_environment_variables=apply_environment_variables, - private_keys_password=private_keys_password, ) if keys_file is not None: @@ -265,7 +266,11 @@ def read_keys(self, keys_file: Path) -> None: ) from e for key in keys: - if {KEY_SCHEMA_ADDRESS, KEY_SCHEMA_PRIVATE_KEY} != set(key.keys()): + if {KEY_SCHEMA_ADDRESS, KEY_SCHEMA_PRIVATE_KEY} != set(key.keys()) and { + KEY_SCHEMA_ADDRESS, + KEY_SCHEMA_PRIVATE_KEY, + KEY_SCHEMA_TYPE, + } != set(key.keys()): raise NotValidKeysFile("Key file incorrectly formatted.") if self.agent_instances is not None: @@ -365,13 +370,20 @@ def _update_tendermint_params( param_args[TENDERMINT_URL_PARAM] = TENDERMINT_NODE_LOCAL param_args[TENDERMINT_COM_URL_PARAM] = TENDERMINT_COM_LOCAL else: - param_args[TENDERMINT_URL_PARAM] = TENDERMINT_NODE.format(idx) - param_args[TENDERMINT_COM_URL_PARAM] = TENDERMINT_COM.format(idx) + param_args[TENDERMINT_URL_PARAM] = TENDERMINT_NODE.format( + host=self.get_tm_container_name(index=idx) + ) + param_args[TENDERMINT_COM_URL_PARAM] = TENDERMINT_COM.format( + host=self.get_tm_container_name(index=idx) + ) if TENDERMINT_P2P_URL_PARAM not in param_args: tm_p2p_url = os.environ.get( TENDERMINT_P2P_URL_ENV_VAR.format(idx), - TENDERMINT_P2P_URL.format(idx, TENDERMINT_P2P_PORT), + TENDERMINT_P2P_URL.format( + host=self.get_tm_container_name(index=idx), + port=TENDERMINT_P2P_PORT, + ), ) param_args[TENDERMINT_P2P_URL_PARAM] = tm_p2p_url @@ -483,7 +495,7 @@ def _update_abci_connection_config( processed_overrides["config"]["host"] = ( LOCALHOST if self.deplopyment_type == KUBERNETES_DEPLOYMENT - else ABCI_HOST_TEMPLATE.format(0) + else self.get_abci_container_name(index=0) ) processed_overrides["config"]["port"] = processed_overrides["config"].get( "port", DEFAULT_ABCI_PORT @@ -499,7 +511,7 @@ def _update_abci_connection_config( override["config"]["host"] = ( LOCALHOST if self.deplopyment_type == KUBERNETES_DEPLOYMENT - else ABCI_HOST_TEMPLATE.format(idx) + else self.get_abci_container_name(index=idx) ) override["config"]["port"] = override["config"].get( "port", DEFAULT_ABCI_PORT @@ -559,7 +571,7 @@ def try_update_abci_connection_params( override for override in service_overrides if override["public_id"] != str(component_id.public_id) - and override["type"] != PackageType.CONNECTION.value + or override["type"] != PackageType.CONNECTION.value ] service_overrides.append(processed_overrides) @@ -604,10 +616,12 @@ def generate_common_vars(self, agent_n: int) -> Dict: ENV_VAR_AEA_AGENT: self.service.agent, ENV_VAR_LOG_LEVEL: self.log_level, } - - if self.private_keys_password is not None: - agent_vars[ENV_VAR_AEA_PASSWORD] = self.private_keys_password - + if self.deplopyment_type == DOCKER_COMPOSE_DEPLOYMENT: + agent_vars[ENV_VAR_AEA_PASSWORD] = "$OPEN_AUTONOMY_PRIVATE_KEY_PASSWORD" + else: + agent_vars[ENV_VAR_AEA_PASSWORD] = os.environ.get( + "OPEN_AUTONOMY_PRIVATE_KEY_PASSWORD", "" + ) return agent_vars def generate_agent( diff --git a/autonomy/deploy/build.py b/autonomy/deploy/build.py index 0f27ca4ac9..d4d3b9d8a2 100644 --- a/autonomy/deploy/build.py +++ b/autonomy/deploy/build.py @@ -38,7 +38,6 @@ def generate_deployment( # pylint: disable=too-many-arguments, too-many-locals service_path: Path, build_dir: Path, number_of_agents: Optional[int] = None, - private_keys_password: Optional[str] = None, dev_mode: bool = False, packages_dir: Optional[Path] = None, open_aea_dir: Optional[Path] = None, @@ -60,7 +59,6 @@ def generate_deployment( # pylint: disable=too-many-arguments, too-many-locals path=service_path, keys_file=keys_file, number_of_agents=number_of_agents, - private_keys_password=private_keys_password, agent_instances=agent_instances, apply_environment_variables=apply_environment_variables, ) diff --git a/autonomy/deploy/constants.py b/autonomy/deploy/constants.py index e11c4a7024..e6caf2e990 100644 --- a/autonomy/deploy/constants.py +++ b/autonomy/deploy/constants.py @@ -39,7 +39,7 @@ KEY_SCHEMA_ADDRESS = "address" KEY_SCHEMA_PRIVATE_KEY = "private_key" - +KEY_SCHEMA_TYPE = "key_type" PERSISTENT_DATA_DIR = "persistent_data" LOG_DIR = "logs" @@ -49,7 +49,6 @@ AGENT_KEYS_DIR = "agent_keys" DOCKERFILES = "Dockerfiles" - INFO = "INFO" DEBUG = "DEBUG" WARNING = "WARNING" diff --git a/autonomy/deploy/generators/docker_compose/base.py b/autonomy/deploy/generators/docker_compose/base.py index 1ea9537550..814ec6fdc7 100644 --- a/autonomy/deploy/generators/docker_compose/base.py +++ b/autonomy/deploy/generators/docker_compose/base.py @@ -18,10 +18,11 @@ # ------------------------------------------------------------------------------ """Docker-compose Deployment Generator.""" +import ipaddress from pathlib import Path -from typing import Dict, Optional +from typing import Dict, Optional, cast -from aea.configurations.constants import DEFAULT_PRIVATE_KEY_FILE +from aea.configurations.constants import DEFAULT_LEDGER, PRIVATE_KEY_PATH_SCHEMA from docker import from_env from autonomy.constants import ( @@ -34,13 +35,14 @@ TENDERMINT_IMAGE_NAME, TENDERMINT_IMAGE_VERSION, ) -from autonomy.deploy.base import BaseDeploymentGenerator +from autonomy.deploy.base import BaseDeploymentGenerator, tm_write_to_log from autonomy.deploy.constants import ( DEFAULT_ENCODING, DEPLOYMENT_AGENT_KEY_DIRECTORY_SCHEMA, DEPLOYMENT_KEY_DIRECTORY, INFO, KEY_SCHEMA_PRIVATE_KEY, + KEY_SCHEMA_TYPE, ) from autonomy.deploy.generators.docker_compose.templates import ( ABCI_NODE_TEMPLATE, @@ -54,43 +56,62 @@ ) -# We will add one ACN and hardhat nodes at the top with IP being 192.167.11.2 -# and 192.167.11.3 so we will start from 192.167.11.4 for abci and tendermint nodes -N_RESERVED_IP_ADDRESSES = 4 +NETWORK_ADDRESS_OFFSET = 1 +BASE_SUBNET = cast(ipaddress.IPv4Network, ipaddress.ip_network("192.167.11.0/24")) +SUBNET_OVERFLOW = 256 DEFAULT_PACKAGES_PATH = Path.cwd().absolute() / "packages" DEFAULT_OPEN_AEA_DIR: Path = Path.home().absolute() / "open-aea" DEFAULT_OPEN_AUTONOMY_DIR: Path = Path.home().absolute() / "open-autonomy" -def build_tendermint_node_config( +def build_tendermint_node_config( # pylint: disable=too-many-arguments node_id: int, + container_name: str, + abci_node: str, + network_name: str, + network_address: str, dev_mode: bool = False, log_level: str = INFO, + tendermint_ports: Optional[Dict[int, int]] = None, ) -> str: """Build tendermint node config for docker compose.""" - config = TENDERMINT_NODE_TEMPLATE.format( node_id=node_id, - localnet_address_postfix=node_id + N_RESERVED_IP_ADDRESSES, + container_name=container_name, + abci_node=abci_node, + network_address=network_address, localnet_port_range=node_id, log_level=log_level, tendermint_image_name=TENDERMINT_IMAGE_NAME, tendermint_image_version=TENDERMINT_IMAGE_VERSION, + network_name=network_name, + write_to_log=str(tm_write_to_log()).lower(), ) if dev_mode: config += " - ./persistent_data/tm_state:/tm_state:Z" config = config.replace("DEV_MODE=0", "DEV_MODE=1") + if tendermint_ports is not None: + port_mappings = map( + lambda x: PORT_MAPPING_CONFIG.format(host_port=x[0], container_port=x[1]), + tendermint_ports.items(), + ) + port_config = "\n".join([PORTS, *port_mappings]) + config += port_config + config += "\n" + return config def build_agent_config( # pylint: disable=too-many-arguments node_id: int, - number_of_agents: int, + container_name: str, agent_vars: Dict, runtime_image: str, + network_name: str, + network_address: str, dev_mode: bool = False, package_dir: Path = DEFAULT_PACKAGES_PATH, open_aea_dir: Path = DEFAULT_OPEN_AEA_DIR, @@ -102,9 +123,11 @@ def build_agent_config( # pylint: disable=too-many-arguments agent_vars_string = "\n".join([f" - {k}={v}" for k, v in agent_vars.items()]) config = ABCI_NODE_TEMPLATE.format( node_id=node_id, + container_name=container_name, agent_vars=agent_vars_string, - localnet_address_postfix=node_id + number_of_agents + N_RESERVED_IP_ADDRESSES, + network_address=network_address, runtime_image=runtime_image, + network_name=network_name, ) if dev_mode: @@ -123,10 +146,63 @@ def build_agent_config( # pylint: disable=too-many-arguments ) port_config = "\n".join([PORTS, *port_mappings]) config += port_config + config += "\n" return config +class Network: + """Class to represent network of the service.""" + + def __init__( + self, + name: str, + base: ipaddress.IPv4Network = BASE_SUBNET, + ) -> None: + """Initialize.""" + self.name = name + self.base = base + self.subnet = self.build() + + self._address_offeset = NETWORK_ADDRESS_OFFSET + + @staticmethod + def next_subnet(subnet: ipaddress.IPv4Network) -> ipaddress.IPv4Network: + """Calculat next available subnet.""" + new_address = subnet.network_address + SUBNET_OVERFLOW + return cast( + ipaddress.IPv4Network, + ipaddress.ip_network(f"{new_address}/{subnet.prefixlen}"), + ) + + def build( + self, + ) -> ipaddress.IPv4Network: + """Initialize network params.""" + docker = from_env() + used_subnets = set() + for network in docker.networks.list(): + # Network already exists + if f"abci_build_{self.name}" == network.attrs["Name"]: + config, *_ = network.attrs["IPAM"]["Config"] + return cast( + ipaddress.IPv4Network, ipaddress.ip_network(config["Subnet"]) + ) + for config in network.attrs["IPAM"]["Config"]: + used_subnets.add(config["Subnet"]) + + subnet = self.base + while str(subnet) in used_subnets: + subnet = self.next_subnet(subnet=subnet) + return subnet + + @property + def next_address(self) -> str: + """Returns the next IP address string.""" + self._address_offeset += 1 + return str(self.subnet.network_address + self._address_offeset) + + class DockerComposeGenerator(BaseDeploymentGenerator): """Class to automate the generation of Deployments.""" @@ -139,13 +215,11 @@ def generate_config_tendermint(self) -> "DockerComposeGenerator": if not self.use_tm_testnet_setup: return self - hosts = ( - " \\\n".join( - [ - f"--hostname=node{k}" - for k in range(self.service_builder.service.number_of_agents) - ] - ), + hosts = " ".join( + [ + "--hostname=" + self.service_builder.get_tm_container_name(index=k) + for k in range(self.service_builder.service.number_of_agents) + ] ) self.tendermint_job_config = TENDERMINT_CONFIG_TEMPLATE.format( validators=self.service_builder.service.number_of_agents, hosts=hosts @@ -170,6 +244,8 @@ def generate( ) -> "DockerComposeGenerator": """Generate the new configuration.""" + network_name = f"service_{self.service_builder.service.name}_localnet" + network = Network(name=network_name) image_version = image_version or self.service_builder.service.agent.hash if self.dev_mode: image_version = "dev" @@ -180,12 +256,13 @@ def generate( version=image_version, ) agent_vars = self.service_builder.generate_agents() - agents = "".join( [ build_agent_config( node_id=i, - number_of_agents=self.service_builder.service.number_of_agents, + container_name=self.service_builder.get_abci_container_name( + index=i + ), runtime_image=runtime_image, agent_vars=agent_vars[i], dev_mode=self.dev_mode, @@ -197,6 +274,8 @@ def generate( .get("ports", {}) .get(i) ), + network_name=network_name, + network_address=network.next_address, ) for i in range(self.service_builder.service.number_of_agents) ] @@ -205,8 +284,19 @@ def generate( [ build_tendermint_node_config( node_id=i, + container_name=self.service_builder.get_tm_container_name(index=i), + abci_node=self.service_builder.get_abci_container_name(index=i), dev_mode=self.dev_mode, log_level=self.service_builder.log_level, + tendermint_ports=( + self.service_builder.service.deployment_config.get( + "tendermint", {} + ) + .get("ports", {}) + .get(i) + ), + network_name=network_name, + network_address=network.next_address, ) for i in range(self.service_builder.service.number_of_agents) ] @@ -217,6 +307,8 @@ def generate( hardhat_node = HARDHAT_NODE_TEMPLATE.format( hardhat_image_name=HARDHAT_IMAGE_NAME, hardhat_image_version=HARDHAT_IMAGE_VERSION, + network_name=network_name, + network_address=network.next_address, ) acn_node = "" @@ -224,6 +316,8 @@ def generate( acn_node = ACN_NODE_TEMPLATE.format( acn_image_name=ACN_IMAGE_NAME, acn_image_version=ACN_IMAGE_VERSION, + network_name=network_name, + network_address=network.next_address, ) self.output = DOCKER_COMPOSE_TEMPLATE.format( @@ -231,6 +325,8 @@ def generate( tendermint_nodes=tendermint_nodes, hardhat_node=hardhat_node, acn_node=acn_node, + network_name=network_name, + subnet=str(network.subnet), ) return self @@ -242,9 +338,9 @@ def populate_private_keys( keys_dir = self.build_dir / DEPLOYMENT_KEY_DIRECTORY for x in range(self.service_builder.service.number_of_agents): path = keys_dir / DEPLOYMENT_AGENT_KEY_DIRECTORY_SCHEMA.format(agent_n=x) - keys_file = path / DEFAULT_PRIVATE_KEY_FILE + ledger = self.service_builder.keys[x].get(KEY_SCHEMA_TYPE, DEFAULT_LEDGER) key = self.service_builder.keys[x][KEY_SCHEMA_PRIVATE_KEY] - + keys_file = path / PRIVATE_KEY_PATH_SCHEMA.format(ledger) path.mkdir() with keys_file.open(mode="w", encoding=DEFAULT_ENCODING) as f: f.write(key) diff --git a/autonomy/deploy/generators/docker_compose/templates.py b/autonomy/deploy/generators/docker_compose/templates.py index 90992708cb..82a9879721 100644 --- a/autonomy/deploy/generators/docker_compose/templates.py +++ b/autonomy/deploy/generators/docker_compose/templates.py @@ -20,23 +20,18 @@ """Deployment Templates.""" -TENDERMINT_CONFIG_TEMPLATE: str = """/usr/bin/tendermint testnet \ - --config /etc/tendermint/config-template.toml \ - --v {validators} \ - --o . \ - {hosts} -""" +TENDERMINT_CONFIG_TEMPLATE: str = """/usr/bin/tendermint testnet --config /etc/tendermint/config-template.toml --v {validators} --o . {hosts}""" DOCKER_COMPOSE_TEMPLATE: str = """version: "2.4" services: {hardhat_node}{acn_node}{tendermint_nodes}{abci_nodes} networks: - localnet: + {network_name}: driver: bridge ipam: driver: default config: - - subnet: 192.167.11.0/24 + - subnet: {subnet} """ ACN_NODE_TEMPLATE: str = """ acn: @@ -51,8 +46,8 @@ - AEA_P2P_URI_MONITORING=0.0.0.0:8081 entrypoint: ["python3", "-u", "/acn/node/run_acn_node_standalone.py", "/acn/node/libp2p_node", "--config-from-env"] networks: - localnet: - ipv4_address: 192.167.11.3 + {network_name}: + ipv4_address: {network_address} ports: - "9005:9005" - "11000:11000" @@ -64,54 +59,55 @@ ports: - "8545:8545" networks: - localnet: - ipv4_address: 192.167.11.2 + {network_name}: + ipv4_address: {network_address} """ TENDERMINT_NODE_TEMPLATE: str = """ - node{node_id}: + {container_name}: mem_limit: 1024m mem_reservation: 256M cpus: 0.5 - container_name: node{node_id} - hostname: node{node_id} + container_name: {container_name} + hostname: {container_name} image: "{tendermint_image_name}:{tendermint_image_version}" restart: always environment: - ID={node_id} - - PROXY_APP=tcp://abci{node_id}:26658 + - PROXY_APP=tcp://{abci_node}:26658 - TMHOME=/tendermint/node{node_id} - CREATE_EMPTY_BLOCKS=true - DEV_MODE=0 - LOG_FILE=/logs/node_{node_id}.txt - LOG_LEVEL={log_level} + - WRITE_TO_LOG={write_to_log} working_dir: /tendermint command: ["run", "--no-reload", "--host=0.0.0.0", "--port=8080",] depends_on: - abci{node_id}: + {abci_node}: condition: service_healthy networks: - localnet: - ipv4_address: 192.167.11.{localnet_address_postfix} + {network_name}: + ipv4_address: {network_address} volumes: - ./nodes:/tendermint:Z - ./persistent_data/logs:/logs:Z """ ABCI_NODE_TEMPLATE: str = """ - abci{node_id}: + {container_name}: mem_limit: 1024m mem_reservation: 256M cpus: 1 - container_name: abci{node_id} + container_name: {container_name} image: {runtime_image} environment: - PYTHONHASHSEED=0 - LOG_FILE=/logs/aea_{node_id}.txt {agent_vars} networks: - localnet: - ipv4_address: 192.167.11.{localnet_address_postfix} + {network_name}: + ipv4_address: {network_address} extra_hosts: - "host.docker.internal:host-gateway" volumes: diff --git a/autonomy/deploy/generators/kubernetes/base.py b/autonomy/deploy/generators/kubernetes/base.py index d972d1c055..07b1bd05ad 100644 --- a/autonomy/deploy/generators/kubernetes/base.py +++ b/autonomy/deploy/generators/kubernetes/base.py @@ -23,6 +23,7 @@ from typing import Any, Dict, List, Optional, cast import yaml +from aea.configurations.constants import DEFAULT_LEDGER from autonomy.constants import ( HARDHAT_IMAGE_NAME, @@ -31,10 +32,15 @@ TENDERMINT_IMAGE_NAME, TENDERMINT_IMAGE_VERSION, ) -from autonomy.deploy.base import BaseDeploymentGenerator, ServiceBuilder +from autonomy.deploy.base import ( + BaseDeploymentGenerator, + ServiceBuilder, + tm_write_to_log, +) from autonomy.deploy.constants import ( DEFAULT_ENCODING, KEY_SCHEMA_PRIVATE_KEY, + KEY_SCHEMA_TYPE, KUBERNETES_AGENT_KEY_NAME, ) from autonomy.deploy.generators.kubernetes.templates import ( @@ -111,6 +117,10 @@ def build_agent_deployment( tendermint_image_version=TENDERMINT_IMAGE_VERSION, log_level=self.service_builder.log_level, agent_ports_deployment=agent_ports_deployment, + ledger=self.service_builder.keys[agent_ix].get( + KEY_SCHEMA_TYPE, DEFAULT_LEDGER + ), + write_to_log=str(tm_write_to_log()).lower(), ) agent_deployment_yaml = yaml.load_all(agent_deployment, Loader=yaml.FullLoader) # type: ignore resources = [] @@ -217,8 +227,11 @@ def populate_private_keys(self) -> "BaseDeploymentGenerator": """Populates private keys into a config map for the kubernetes deployment.""" path = self.build_dir / "agent_keys" for x in range(self.service_builder.service.number_of_agents): + ledger = self.service_builder.keys[x].get(KEY_SCHEMA_TYPE, DEFAULT_LEDGER) key = self.service_builder.keys[x][KEY_SCHEMA_PRIVATE_KEY] - secret = AGENT_SECRET_TEMPLATE.format(private_key=key, validator_ix=x) + secret = AGENT_SECRET_TEMPLATE.format( + private_key=key, validator_ix=x, ledger=ledger + ) with open( path / KUBERNETES_AGENT_KEY_NAME.format(agent_n=x), "w", encoding="utf8" ) as f: diff --git a/autonomy/deploy/generators/kubernetes/templates.py b/autonomy/deploy/generators/kubernetes/templates.py index 155ce12870..711d1e010c 100644 --- a/autonomy/deploy/generators/kubernetes/templates.py +++ b/autonomy/deploy/generators/kubernetes/templates.py @@ -231,6 +231,8 @@ value: "/logs/node_{validator_ix}.txt" - name: LOG_LEVEL value: {log_level} + - name: WRITE_TO_LOG + value: "{write_to_log}" args: ["run", "--no-reload", "--host=0.0.0.0", "--port=8080"] volumeMounts: - mountPath: /tm_state @@ -274,8 +276,8 @@ secret: secretName: agent-validator-{validator_ix}-key items: - - key: private_key - path: ethereum_private_key.txt + - key: {ledger}_private_key.txt + path: {ledger}_private_key.txt - name: persistent-data persistentVolumeClaim: claimName: 'logs-pvc' @@ -306,7 +308,7 @@ AGENT_SECRET_TEMPLATE: str = """ apiVersion: v1 stringData: - private_key: '{private_key}' + {ledger}_private_key.txt: '{private_key}' kind: Secret metadata: annotations: diff --git a/autonomy/deploy/image.py b/autonomy/deploy/image.py index de11f655d2..8707256db7 100644 --- a/autonomy/deploy/image.py +++ b/autonomy/deploy/image.py @@ -21,10 +21,11 @@ import json -from typing import Dict, Optional +from pathlib import Path +from typing import Dict, Optional, Tuple from aea.cli.utils.config import get_default_author_from_cli_config -from aea.configurations.utils import PublicId +from aea.configurations.data_types import Dependency, PublicId from docker import from_env from autonomy.constants import ( @@ -37,6 +38,16 @@ from autonomy.deploy.constants import DOCKERFILES +def generate_dependency_flag_var(dependencies: Tuple[Dependency, ...]) -> str: + """Generate dependency flag env var""" + args = [] + for dep in dependencies: + # Flag for `aea install` command + args += ["-e"] + args += dep.get_pip_install_args() + return " ".join(args) + + class ImageProfiles: # pylint: disable=too-few-public-methods """Image build profiles.""" @@ -46,39 +57,38 @@ class ImageProfiles: # pylint: disable=too-few-public-methods ALL = (CLUSTER, DEVELOPMENT, PRODUCTION) -def build_image( +def build_image( # pylint: disable=too-many-arguments,too-many-locals agent: PublicId, pull: bool = False, dev: bool = False, version: Optional[str] = None, image_author: Optional[str] = None, + extra_dependencies: Optional[Tuple[Dependency, ...]] = None, + dockerfile: Optional[Path] = None, ) -> None: """Command to build images from for skaffold deployment.""" tag: str path: str buildargs: Dict[str, str] - docker_client = from_env() + buildargs = { + "AUTONOMY_IMAGE_NAME": AUTONOMY_IMAGE_NAME, + "AUTONOMY_IMAGE_VERSION": AUTONOMY_IMAGE_VERSION, + "AEA_AGENT": str(agent), + "AUTHOR": get_default_author_from_cli_config(), + "EXTRA_DEPENDENCIES": generate_dependency_flag_var(extra_dependencies or ()), + } if dev: path = str(DATA_DIR / DOCKERFILES / "dev") - buildargs = { - "AUTONOMY_IMAGE_NAME": AUTONOMY_IMAGE_NAME, - "AUTONOMY_IMAGE_VERSION": AUTONOMY_IMAGE_VERSION, - "AEA_AGENT": str(agent), - "AUTHOR": get_default_author_from_cli_config(), - } - else: image_version = version or agent.hash path = str(DATA_DIR / DOCKERFILES / "agent") - buildargs = { - "AUTONOMY_IMAGE_NAME": AUTONOMY_IMAGE_NAME, - "AUTONOMY_IMAGE_VERSION": AUTONOMY_IMAGE_VERSION, - "AEA_AGENT": str(agent), - "AUTHOR": get_default_author_from_cli_config(), - } + + if dockerfile is not None: # pragma: nocover + path = str(Path(dockerfile).parent) + tag = OAR_IMAGE.format( image_author=image_author or DEFAULT_DOCKER_IMAGE_AUTHOR, agent=agent.name, diff --git a/autonomy/fsm/scaffold/scaffold_skill.py b/autonomy/fsm/scaffold/scaffold_skill.py index eb704bf672..e9e8a2d8c4 100644 --- a/autonomy/fsm/scaffold/scaffold_skill.py +++ b/autonomy/fsm/scaffold/scaffold_skill.py @@ -20,6 +20,7 @@ """Scaffold skill from an FSM""" +import itertools import os import re import shutil @@ -180,14 +181,19 @@ def get_actual_abstract_round_abci_package_public_id( package_manager = PackageManagerV1.from_dir(Path(ctx.registry_path)) packages = [ package_id.public_id - for package_id in package_manager.dev_packages.keys() - if package_id.author == ABSTRACT_ROUND_SKILL_PUBLIC_ID.author - and package_id.name == ABSTRACT_ROUND_SKILL_PUBLIC_ID.name - and package_id.package_type == PackageType.SKILL + for package_id in itertools.chain( + package_manager.third_party_packages.keys(), + package_manager.dev_packages.keys(), + ) + if ( + package_id.public_id.without_hash().to_any() + == ABSTRACT_ROUND_SKILL_PUBLIC_ID.without_hash().to_any() + and package_id.package_type == PackageType.SKILL + ) ] if not packages: return None - abstract_round_abci = packages[0] + abstract_round_abci, *_ = packages return abstract_round_abci def _update_dependencies(self, config: SkillConfig) -> None: @@ -337,7 +343,7 @@ def do_scaffolding(self) -> None: file_dirs = self.skill_dir, self.skill_test_dir file_gens = self.file_generators, self.test_file_generators - for (f_dir, gens) in zip(file_dirs, file_gens): + for f_dir, gens in zip(file_dirs, file_gens): for f_gen in gens: click.echo(f"Generating module {f_gen.FILENAME}...") f_gen(self.ctx, self.skill_name, self.dfa).write_file(f_dir) diff --git a/autonomy/fsm/scaffold/templates/components.py b/autonomy/fsm/scaffold/templates/components.py index 1824f22ad2..6a9a7ba7a4 100644 --- a/autonomy/fsm/scaffold/templates/components.py +++ b/autonomy/fsm/scaffold/templates/components.py @@ -32,7 +32,7 @@ class ROUNDS: \"\"\"This package contains the rounds of {AbciApp}.\"\"\" from enum import Enum - from typing import Dict, List, Optional, Set, Tuple + from typing import Dict, FrozenSet, List, Optional, Set, Tuple from packages.valory.skills.abstract_round_abci.base import ( AbciApp, @@ -103,7 +103,7 @@ class {AbciApp}(AbciApp[Event]): transition_function: AbciAppTransitionFunction = {transition_function} final_states: Set[AppState] = {final_states} event_to_timeout: EventToTimeout = {{}} - cross_period_persisted_keys: Set[str] = [] + cross_period_persisted_keys: FrozenSet[str] = frozenset() db_pre_conditions: Dict[AppState, Set[str]] = {{ {db_pre_conditions} }} diff --git a/autonomy/replay/agent.py b/autonomy/replay/agent.py index 3395087e6e..d6ada2032b 100644 --- a/autonomy/replay/agent.py +++ b/autonomy/replay/agent.py @@ -29,11 +29,11 @@ from tempfile import TemporaryDirectory from typing import Dict, List, Optional -from aea_ledger_ethereum.test_tools.constants import ETHEREUM_PRIVATE_KEY_FILE - from autonomy.deploy.base import TENDERMINT_COM_URL_PARAM, TENDERMINT_URL_PARAM +ETHEREUM_PRIVATE_KEY_FILE = "ethereum_private_key.txt" + CONNECTION_ABCI_CONFIG_HOST = "CONNECTION_ABCI_CONFIG_HOST" CONNECTION_ABCI_CONFIG_PORT = "CONNECTION_ABCI_CONFIG_PORT" diff --git a/autonomy/services/scaffold/service.yaml b/autonomy/services/scaffold/service.yaml index 1abe78e984..2b7a648b68 100644 --- a/autonomy/services/scaffold/service.yaml +++ b/autonomy/services/scaffold/service.yaml @@ -7,3 +7,5 @@ license: Apache-2.0 agent: agent network: hardhat number_of_agents: 4 +deployment: {} +dependencies: {} \ No newline at end of file diff --git a/deployments/Dockerfiles/autonomy-user/requirements.txt b/deployments/Dockerfiles/autonomy-user/requirements.txt index 26f2952720..a5199286ef 100644 --- a/deployments/Dockerfiles/autonomy-user/requirements.txt +++ b/deployments/Dockerfiles/autonomy-user/requirements.txt @@ -1,5 +1,5 @@ -open-autonomy[all]==0.10.2 -open-aea[all]==1.32.0 -open-aea-cli-ipfs==1.32.0 -open-aea-ledger-ethereum==1.32.0 -protobuf>=3.20,<=3.20.1 +open-autonomy[all]==0.13.9.post1 +open-aea[all]==1.43.0.post2 +open-aea-cli-ipfs==1.43.0.post2 +open-aea-ledger-ethereum==1.43.0.post2 +protobuf>=4.21.6,<5.0.0 diff --git a/deployments/Dockerfiles/autonomy/Dockerfile b/deployments/Dockerfiles/autonomy/Dockerfile index bc4aee69f0..dafb3c5496 100644 --- a/deployments/Dockerfiles/autonomy/Dockerfile +++ b/deployments/Dockerfiles/autonomy/Dockerfile @@ -2,24 +2,10 @@ ARG AEA_VERSION=latest FROM valory/open-aea-user:${AEA_VERSION} -COPY openssl.cnf /etc/ssl -COPY requirements.txt /home/ubuntu +RUN apt update -WORKDIR /home/ubuntu -ENV PATH=$PATH:/home/ubuntu/.local/bin +RUN apt install git net-tools sudo -y -RUN sudo apt-get update --fix-missing -RUN sudo apt-get autoremove -RUN sudo apt-get autoclean -RUN sudo apt-get install python3.10 python3.10-dev git -y -RUN cd /usr/bin && sudo rm python3 && sudo ln -s python3.10 python3 && sudo ln -s python3.10 python +COPY scripts /root/scripts -# used in Docker-compose to wait until Hardhat node is up -RUN sudo apt-get install net-tools -y -RUN python -m pip install --upgrade pip - -WORKDIR /home/ubuntu - -RUN pip3 install -r requirements.txt - -ENTRYPOINT [ "/bin/bash" ] +ENTRYPOINT ["/bin/bash", "-c"] diff --git a/deployments/Dockerfiles/autonomy/openssl.cnf b/deployments/Dockerfiles/autonomy/openssl.cnf deleted file mode 100644 index acbe687d89..0000000000 --- a/deployments/Dockerfiles/autonomy/openssl.cnf +++ /dev/null @@ -1,365 +0,0 @@ -# -# OpenSSL example configuration file. -# This is mostly being used for generation of certificate requests. -# - -# Note that you can include other files from the main configuration -# file using the .include directive. -#.include filename - -# This definition stops the following lines choking if HOME isn't -# defined. -HOME = . - -openssl_conf = openssl_init - -[openssl_init] -providers = provider_sect - -[provider_sect] -default = default_sect -legacy = legacy_sect - -[default_sect] -activate = 1 - -[legacy_sect] -activate = 1 - -# Extra OBJECT IDENTIFIER info: -#oid_file = $ENV::HOME/.oid -oid_section = new_oids - -# To use this configuration file with the "-extfile" option of the -# "openssl x509" utility, name here the section containing the -# X.509v3 extensions to use: -# extensions = -# (Alternatively, use a configuration file that has only -# X.509v3 extensions in its main [= default] section.) - -[ new_oids ] - -# We can add new OIDs in here for use by 'ca', 'req' and 'ts'. -# Add a simple OID like this: -# testoid1=1.2.3.4 -# Or use config file substitution like this: -# testoid2=${testoid1}.5.6 - -# Policies used by the TSA examples. -tsa_policy1 = 1.2.3.4.1 -tsa_policy2 = 1.2.3.4.5.6 -tsa_policy3 = 1.2.3.4.5.7 - -#################################################################### -[ ca ] -default_ca = CA_default # The default ca section - -#################################################################### -[ CA_default ] - -dir = ./demoCA # Where everything is kept -certs = $dir/certs # Where the issued certs are kept -crl_dir = $dir/crl # Where the issued crl are kept -database = $dir/index.txt # database index file. -#unique_subject = no # Set to 'no' to allow creation of - # several certs with same subject. -new_certs_dir = $dir/newcerts # default place for new certs. - -certificate = $dir/cacert.pem # The CA certificate -serial = $dir/serial # The current serial number -crlnumber = $dir/crlnumber # the current crl number - # must be commented out to leave a V1 CRL -crl = $dir/crl.pem # The current CRL -private_key = $dir/private/cakey.pem# The private key - -x509_extensions = usr_cert # The extensions to add to the cert - -# Comment out the following two lines for the "traditional" -# (and highly broken) format. -name_opt = ca_default # Subject Name options -cert_opt = ca_default # Certificate field options - -# Extension copying option: use with caution. -# copy_extensions = copy - -# Extensions to add to a CRL. Note: Netscape communicator chokes on V2 CRLs -# so this is commented out by default to leave a V1 CRL. -# crlnumber must also be commented out to leave a V1 CRL. -# crl_extensions = crl_ext - -default_days = 365 # how long to certify for -default_crl_days= 30 # how long before next CRL -default_md = default # use public key default MD -preserve = no # keep passed DN ordering - -# A few difference way of specifying how similar the request should look -# For type CA, the listed attributes must be the same, and the optional -# and supplied fields are just that :-) -policy = policy_match - -# For the CA policy -[ policy_match ] -countryName = match -stateOrProvinceName = match -organizationName = match -organizationalUnitName = optional -commonName = supplied -emailAddress = optional - -# For the 'anything' policy -# At this point in time, you must list all acceptable 'object' -# types. -[ policy_anything ] -countryName = optional -stateOrProvinceName = optional -localityName = optional -organizationName = optional -organizationalUnitName = optional -commonName = supplied -emailAddress = optional - -#################################################################### -[ req ] -default_bits = 2048 -default_keyfile = privkey.pem -distinguished_name = req_distinguished_name -attributes = req_attributes -x509_extensions = v3_ca # The extensions to add to the self signed cert - -# Passwords for private keys if not present they will be prompted for -# input_password = secret -# output_password = secret - -# This sets a mask for permitted string types. There are several options. -# default: PrintableString, T61String, BMPString. -# pkix : PrintableString, BMPString (PKIX recommendation before 2004) -# utf8only: only UTF8Strings (PKIX recommendation after 2004). -# nombstr : PrintableString, T61String (no BMPStrings or UTF8Strings). -# MASK:XXXX a literal mask value. -# WARNING: ancient versions of Netscape crash on BMPStrings or UTF8Strings. -string_mask = utf8only - -# req_extensions = v3_req # The extensions to add to a certificate request - -[ req_distinguished_name ] -countryName = Country Name (2 letter code) -countryName_default = AU -countryName_min = 2 -countryName_max = 2 - -stateOrProvinceName = State or Province Name (full name) -stateOrProvinceName_default = Some-State - -localityName = Locality Name (eg, city) - -0.organizationName = Organization Name (eg, company) -0.organizationName_default = Internet Widgits Pty Ltd - -# we can do this but it is not needed normally :-) -#1.organizationName = Second Organization Name (eg, company) -#1.organizationName_default = World Wide Web Pty Ltd - -organizationalUnitName = Organizational Unit Name (eg, section) -#organizationalUnitName_default = - -commonName = Common Name (e.g. server FQDN or YOUR name) -commonName_max = 64 - -emailAddress = Email Address -emailAddress_max = 64 - -# SET-ex3 = SET extension number 3 - -[ req_attributes ] -challengePassword = A challenge password -challengePassword_min = 4 -challengePassword_max = 20 - -unstructuredName = An optional company name - -[ usr_cert ] - -# These extensions are added when 'ca' signs a request. - -# This goes against PKIX guidelines but some CAs do it and some software -# requires this to avoid interpreting an end user certificate as a CA. - -basicConstraints=CA:FALSE - -# Here are some examples of the usage of nsCertType. If it is omitted -# the certificate can be used for anything *except* object signing. - -# This is OK for an SSL server. -# nsCertType = server - -# For an object signing certificate this would be used. -# nsCertType = objsign - -# For normal client use this is typical -# nsCertType = client, email - -# and for everything including object signing: -# nsCertType = client, email, objsign - -# This is typical in keyUsage for a client certificate. -# keyUsage = nonRepudiation, digitalSignature, keyEncipherment - -# This will be displayed in Netscape's comment listbox. -nsComment = "OpenSSL Generated Certificate" - -# PKIX recommendations harmless if included in all certificates. -subjectKeyIdentifier=hash -authorityKeyIdentifier=keyid,issuer - -# This stuff is for subjectAltName and issuerAltname. -# Import the email address. -# subjectAltName=email:copy -# An alternative to produce certificates that aren't -# deprecated according to PKIX. -# subjectAltName=email:move - -# Copy subject details -# issuerAltName=issuer:copy - -#nsCaRevocationUrl = http://www.domain.dom/ca-crl.pem -#nsBaseUrl -#nsRevocationUrl -#nsRenewalUrl -#nsCaPolicyUrl -#nsSslServerName - -# This is required for TSA certificates. -# extendedKeyUsage = critical,timeStamping - -[ v3_req ] - -# Extensions to add to a certificate request - -basicConstraints = CA:FALSE -keyUsage = nonRepudiation, digitalSignature, keyEncipherment - -[ v3_ca ] - - -# Extensions for a typical CA - - -# PKIX recommendation. - -subjectKeyIdentifier=hash - -authorityKeyIdentifier=keyid:always,issuer - -basicConstraints = critical,CA:true - -# Key usage: this is typical for a CA certificate. However since it will -# prevent it being used as an test self-signed certificate it is best -# left out by default. -# keyUsage = cRLSign, keyCertSign - -# Some might want this also -# nsCertType = sslCA, emailCA - -# Include email address in subject alt name: another PKIX recommendation -# subjectAltName=email:copy -# Copy issuer details -# issuerAltName=issuer:copy - -# DER hex encoding of an extension: beware experts only! -# obj=DER:02:03 -# Where 'obj' is a standard or added object -# You can even override a supported extension: -# basicConstraints= critical, DER:30:03:01:01:FF - -[ crl_ext ] - -# CRL extensions. -# Only issuerAltName and authorityKeyIdentifier make any sense in a CRL. - -# issuerAltName=issuer:copy -authorityKeyIdentifier=keyid:always - -[ proxy_cert_ext ] -# These extensions should be added when creating a proxy certificate - -# This goes against PKIX guidelines but some CAs do it and some software -# requires this to avoid interpreting an end user certificate as a CA. - -basicConstraints=CA:FALSE - -# Here are some examples of the usage of nsCertType. If it is omitted -# the certificate can be used for anything *except* object signing. - -# This is OK for an SSL server. -# nsCertType = server - -# For an object signing certificate this would be used. -# nsCertType = objsign - -# For normal client use this is typical -# nsCertType = client, email - -# and for everything including object signing: -# nsCertType = client, email, objsign - -# This is typical in keyUsage for a client certificate. -# keyUsage = nonRepudiation, digitalSignature, keyEncipherment - -# This will be displayed in Netscape's comment listbox. -nsComment = "OpenSSL Generated Certificate" - -# PKIX recommendations harmless if included in all certificates. -subjectKeyIdentifier=hash -authorityKeyIdentifier=keyid,issuer - -# This stuff is for subjectAltName and issuerAltname. -# Import the email address. -# subjectAltName=email:copy -# An alternative to produce certificates that aren't -# deprecated according to PKIX. -# subjectAltName=email:move - -# Copy subject details -# issuerAltName=issuer:copy - -#nsCaRevocationUrl = http://www.domain.dom/ca-crl.pem -#nsBaseUrl -#nsRevocationUrl -#nsRenewalUrl -#nsCaPolicyUrl -#nsSslServerName - -# This really needs to be in place for it to be a proxy certificate. -proxyCertInfo=critical,language:id-ppl-anyLanguage,pathlen:3,policy:foo - -#################################################################### -[ tsa ] - -default_tsa = tsa_config1 # the default TSA section - -[ tsa_config1 ] - -# These are used by the TSA reply generation only. -dir = ./demoCA # TSA root directory -serial = $dir/tsaserial # The current serial number (mandatory) -crypto_device = builtin # OpenSSL engine to use for signing -signer_cert = $dir/tsacert.pem # The TSA signing certificate - # (optional) -certs = $dir/cacert.pem # Certificate chain to include in reply - # (optional) -signer_key = $dir/private/tsakey.pem # The TSA private key (optional) -signer_digest = sha256 # Signing digest to use. (Optional) -default_policy = tsa_policy1 # Policy if request did not specify it - # (optional) -other_policies = tsa_policy2, tsa_policy3 # acceptable policies (optional) -digests = sha1, sha256, sha384, sha512 # Acceptable message digests (mandatory) -accuracy = secs:1, millisecs:500, microsecs:100 # (optional) -clock_precision_digits = 0 # number of digits after dot. (optional) -ordering = yes # Is ordering defined for timestamps? - # (optional, default: no) -tsa_name = yes # Must the TSA name be included in the reply? - # (optional, default: no) -ess_cert_id_chain = no # Must the ESS cert id chain be included? - # (optional, default: no) -ess_cert_id_alg = sha1 # algorithm to compute certificate - # identifier (optional, default: sha1) diff --git a/deployments/Dockerfiles/autonomy/requirements.txt b/deployments/Dockerfiles/autonomy/requirements.txt deleted file mode 100644 index f5c3ac74c5..0000000000 --- a/deployments/Dockerfiles/autonomy/requirements.txt +++ /dev/null @@ -1,8 +0,0 @@ -watchdog==2.1.6 -requests==2.27.1 -open-aea[all]==1.32.0 -open-aea-cli-ipfs==1.32.0 -open-aea-ledger-ethereum==1.32.0 -open-aea-ledger-ethereum-hwi==1.32.0 -open-aea-ledger-cosmos==1.32.0 -protobuf>=3.20,<=3.20.1 \ No newline at end of file diff --git a/deployments/Dockerfiles/autonomy/scripts/install.sh b/deployments/Dockerfiles/autonomy/scripts/install.sh new file mode 100644 index 0000000000..311e8a0f73 --- /dev/null +++ b/deployments/Dockerfiles/autonomy/scripts/install.sh @@ -0,0 +1,24 @@ +#! /bin/bash + +if [ "$AEA_AGENT" == "" ]; +then + echo "No Application specified!" + exit 1 +fi + +echo Running the aea with $(aea --version) + +echo "Loading $AEA_AGENT" +aea fetch $AEA_AGENT --alias agent || exit 1 +cd agent + +echo "Building the deployments host dependencies." +aea build || exit 1 +echo "Successfully built the host dependencies." + +echo "Installing the necessary python dependencies!" +aea install --timeout 600 $EXTRA_DEPENDENCIES || exit 1 +echo "Successfully Installed the python dependecies." + +echo "Done." +cd .. diff --git a/deployments/Dockerfiles/autonomy/scripts/start.sh b/deployments/Dockerfiles/autonomy/scripts/start.sh new file mode 100755 index 0000000000..c33093b798 --- /dev/null +++ b/deployments/Dockerfiles/autonomy/scripts/start.sh @@ -0,0 +1,105 @@ +#! /bin/bash + +# ensure hard exit on any failure +set -e +export PYTHONWARNINGS="ignore" + +# Debug mode +if [ "$DEBUG" == "1" ]; then + echo "Debugging..." + while true; do + echo "waiting" + sleep 2 + done +fi + +function generateKey() { + if [ "$AEA_PASSWORD" != "" ]; then + echo "Generating key $1 with a password!" + aea generate-key $1 --password $AEA_PASSWORD + else + echo "Generating key $1 without a password!" + aea generate-key $1 + fi +} + +function checkKey() { + export FILE=/agent_key/$(echo $1)_private_key.txt + echo "Checking to see if $FILE exists" + if [ -f "$FILE" ]; then + echo "AEA key provided. Copying to agent." + cp $FILE . + else + # we now check the dependecies, and generate keys we need, if not present. + if grep open-aea-ledger-$1 aea-config.yaml -q; then + echo "AEA key not provided yet is required. Generating." + generateKey $1 + fi + fi + addKey $1 + +} + +function handleFlashbotsKey() { + if grep "open-aea-ledger-ethereum-flashbots" aea-config.yaml -q; then + echo "Copying ethereum key to ethereum flashbots key" + cp ethereum_private_key.txt ethereum_flashbots_private_key.txt + fi +} + +function handleCosmosConnectionKeyAndCerts() { + echo "Generating cosmos key for libp2p connection" + if [ ! -f "cosmos_private_key.txt" ]; then + generateKey cosmos + fi + + if [[ "$AEA_PASSWORD" != "" ]]; then + echo "Issuing certificates with password" + aea add-key cosmos --connection --password $AEA_PASSWORD + aea issue-certificates --password $AEA_PASSWORD + else + echo "Issuing certificates without password" + aea add-key cosmos --connection + aea issue-certificates + fi +} + +function runAgent() { + if [[ "$AEA_PASSWORD" != "" ]]; then + aea run --password $AEA_PASSWORD + else + aea run + fi + +} + +function addKey() { + FILE=$(echo $1)_private_key.txt + if [ -f "$FILE" ]; then + echo "$1 key provided. Adding to agent." + if [[ "$AEA_PASSWORD" != "" ]]; then + aea add-key $1 --password $AEA_PASSWORD + else + aea add-key $1 + fi + fi +} + +function main() { + echo "Running the aea with $(aea --version)" + echo "Checking keys" + checkKey ethereum + checkKey cosmos + checkKey solana + + echo "Checking autonomy specific connection keys" + handleFlashbotsKey + handleCosmosConnectionKeyAndCerts + + echo "Running the aea" + runAgent + +} + +cd agent +main diff --git a/deployments/Dockerfiles/documentation/Dockerfile b/deployments/Dockerfiles/documentation/Dockerfile index 81f31566a6..5a59356d26 100644 --- a/deployments/Dockerfiles/documentation/Dockerfile +++ b/deployments/Dockerfiles/documentation/Dockerfile @@ -18,7 +18,7 @@ WORKDIR /build COPY docs/ /build/docs COPY mkdocs.yml /build -RUN pip3 install tomte[docs]==0.2.4 +RUN pip3 install tomte[docs]==0.2.15 RUN mkdocs build FROM python:3.10-alpine diff --git a/deployments/Dockerfiles/tendermint/Dockerfile b/deployments/Dockerfiles/tendermint/Dockerfile index 910959eb08..9172426b33 100644 --- a/deployments/Dockerfiles/tendermint/Dockerfile +++ b/deployments/Dockerfiles/tendermint/Dockerfile @@ -13,11 +13,11 @@ COPY wait-for-it.sh . RUN chmod u+x wait-for-it.sh RUN mv wait-for-it.sh /usr/local/bin -# Download Tendermint -RUN curl -L https://github.com/tendermint/tendermint/releases/download/v${TENDERMINT_VERSION}/tendermint_${TENDERMINT_VERSION}_linux_amd64.tar.gz > tendermint.tar.gz &&\ - tar -xf tendermint.tar.gz &&\ - mv tendermint /usr/bin &&\ - rm -fr tendermint.tar.gz +COPY install.sh . +RUN chmod u+x install.sh + +# Install Tendermint +RUN bash install.sh RUN mkdir -p /app /tm_state diff --git a/deployments/Dockerfiles/tendermint/app.py b/deployments/Dockerfiles/tendermint/app.py index 7d5b14f074..6cd2a516c8 100644 --- a/deployments/Dockerfiles/tendermint/app.py +++ b/deployments/Dockerfiles/tendermint/app.py @@ -189,11 +189,10 @@ def dump_period(self) -> None: def create_app( # pylint: disable=too-many-statements dump_dir: Optional[Path] = None, - perform_monitoring: bool = True, debug: bool = False, ) -> Tuple[Flask, TendermintNode]: """Create the Tendermint server app""" - + write_to_log = os.environ.get("WRITE_TO_LOG", "false").lower() == "true" tendermint_params = TendermintParams( proxy_app=os.environ["PROXY_APP"], consensus_create_empty_blocks=os.environ["CREATE_EMPTY_BLOCKS"] == "true", @@ -203,12 +202,14 @@ def create_app( # pylint: disable=too-many-statements app = Flask(__name__) period_dumper = PeriodDumper(logger=app.logger, dump_dir=dump_dir) - tendermint_node = TendermintNode(tendermint_params, logger=app.logger) + tendermint_node = TendermintNode( + tendermint_params, + logger=app.logger, + write_to_log=write_to_log, + ) tendermint_node.init() - override_config_toml() - - tendermint_node.start(start_monitoring=perform_monitoring, debug=debug) + tendermint_node.start(debug=debug) @app.get("/params") def get_params() -> Dict: @@ -266,7 +267,7 @@ def gentle_reset() -> Tuple[Any, int]: """Reset the tendermint node gently.""" try: tendermint_node.stop() - tendermint_node.start(start_monitoring=perform_monitoring) + tendermint_node.start() return jsonify({"message": "Reset successful.", "status": True}), 200 except Exception as e: # pylint: disable=W0703 return jsonify({"message": f"Reset failed: {e}", "status": False}), 200 @@ -298,7 +299,7 @@ def hard_reset() -> Tuple[Any, int]: return_code = tendermint_node.prune_blocks() if return_code: - tendermint_node.start(start_monitoring=perform_monitoring) + tendermint_node.start() raise RuntimeError("Could not perform `unsafe-reset-all` successfully!") defaults = get_defaults() tendermint_node.reset_genesis_file( @@ -307,7 +308,7 @@ def hard_reset() -> Tuple[Any, int]: request.args.get("initial_height", "1"), request.args.get("period_count", "0"), ) - tendermint_node.start(start_monitoring=perform_monitoring) + tendermint_node.start() return jsonify({"message": "Reset successful.", "status": True}), 200 except Exception as e: # pylint: disable=W0703 return jsonify({"message": f"Reset failed: {e}", "status": False}), 200 diff --git a/deployments/Dockerfiles/tendermint/install.sh b/deployments/Dockerfiles/tendermint/install.sh new file mode 100644 index 0000000000..3b75725361 --- /dev/null +++ b/deployments/Dockerfiles/tendermint/install.sh @@ -0,0 +1,18 @@ +# Install architecture specific version of tendermint + +echo Fetching binaries for $(uname -m) +if [[ "$(uname -m)" == "aarch64" ]] +then + curl -L https://github.com/tendermint/tendermint/releases/download/v0.34.19/tendermint_0.34.19_linux_arm64.tar.gz > tendermint.tar.gz +elif [[ "$(uname -m)" == "armv7l" ]] +then + curl -L https://github.com/tendermint/tendermint/releases/download/v0.34.19/tendermint_0.34.19_linux_arm64.tar.gz > tendermint.tar.gz +else + curl -L https://github.com/tendermint/tendermint/releases/download/v0.34.19/tendermint_0.34.19_linux_amd64.tar.gz > tendermint.tar.gz +fi + +tar -xvf tendermint.tar.gz +mv tendermint /usr/bin +rm -fr tendermint.tar.gz + +/usr/bin/tendermint --help \ No newline at end of file diff --git a/deployments/Dockerfiles/tendermint/tendermint.py b/deployments/Dockerfiles/tendermint/tendermint.py index 7c98fd5071..b1c87df0fd 100644 --- a/deployments/Dockerfiles/tendermint/tendermint.py +++ b/deployments/Dockerfiles/tendermint/tendermint.py @@ -24,6 +24,7 @@ import platform import signal import subprocess # nosec: +import sys from logging import Logger from pathlib import Path from threading import Event, Thread @@ -117,47 +118,49 @@ def build_node_command(self, debug: bool = False) -> List[str]: ] if debug: cmd.append("--log_level=debug") - if self.home is not None: # pragma: nocover cmd += ["--home", self.home] return cmd @staticmethod - def get_node_command_kwargs(monitoring: bool = False) -> Dict: + def get_node_command_kwargs() -> Dict: """Get the node command kwargs""" kwargs = { "bufsize": 1, "universal_newlines": True, + "stdout": subprocess.PIPE, + "stderr": subprocess.STDOUT, } - - # Only redirect stdout and stderr if we're going to read - if monitoring: - kwargs["stdout"] = subprocess.PIPE - kwargs["stderr"] = subprocess.STDOUT - if platform.system() == "Windows": # pragma: nocover kwargs["creationflags"] = subprocess.CREATE_NEW_PROCESS_GROUP # type: ignore else: kwargs["preexec_fn"] = os.setsid # type: ignore - return kwargs class TendermintNode: """A class to manage a Tendermint node.""" - def __init__(self, params: TendermintParams, logger: Optional[Logger] = None): + def __init__( + self, + params: TendermintParams, + logger: Optional[Logger] = None, + write_to_log: bool = False, + ): """ Initialize a Tendermint node. :param params: the parameters. :param logger: the logger. + :param write_to_log: Write to log file. """ self.params = params self._process: Optional[subprocess.Popen] = None self._monitoring: Optional[StoppableThread] = None + self._stopping = False self.logger = logger or logging.getLogger() self.log_file = os.environ.get("LOG_FILE", DEFAULT_TENDERMINT_LOG_FILE) + self.write_to_log = write_to_log def _build_init_command(self) -> List[str]: """Build the 'init' command.""" @@ -174,42 +177,74 @@ def init(self) -> None: cmd = self._build_init_command() subprocess.call(cmd) # nosec - def start(self, start_monitoring: bool = False, debug: bool = False) -> None: - """Start a Tendermint node process.""" - self._start_tm_process(start_monitoring, debug) - if start_monitoring: - self._start_monitoring_thread() + def _monitor_tendermint_process( + self, + ) -> None: + """Check server status.""" + if self._monitoring is None: + raise ValueError("Monitoring is not running") + self.log("Monitoring thread started\n") + while not self._monitoring.stopped(): + try: + if self._process is not None and self._process.stdout is not None: + line = self._process.stdout.readline() + self.log(line) + for trigger in [ + # this occurs when we lose connection from the tm side + "RPC HTTP server stopped", + # whenever the node is stopped because of a closed connection + # from on any of the tendermint modules (abci, p2p, rpc, etc) + # we restart the node + "Stopping abci.socketClient for error: read message: EOF", + ]: + if self._monitoring.stopped(): + break + if line.find(trigger) >= 0: + self._stop_tm_process() + # we can only reach this step if monitoring was activated + # so we make sure that after reset the monitoring continues + self._start_tm_process() + self.log( + f"Restarted the HTTP RPC server, as a connection was dropped with message:\n\t\t {line}\n" + ) + except Exception as e: # pylint: disable=broad-except + self.log(f"Error!: {str(e)}") + self.log("Monitoring thread terminated\n") - def _start_tm_process(self, monitoring: bool = False, debug: bool = False) -> None: + def _start_tm_process(self, debug: bool = False) -> None: """Start a Tendermint node process.""" - - if self._process is not None: # pragma: nocover + if self._process is not None or self._stopping: # pragma: nocover return - cmd = self.params.build_node_command(debug) - kwargs = self.params.get_node_command_kwargs(monitoring) - - logging.info(f"Starting Tendermint: {cmd}") + kwargs = self.params.get_node_command_kwargs() + self.log(f"Starting Tendermint: {cmd}\n") self._process = ( subprocess.Popen( # nosec # pylint: disable=consider-using-with,W1509 cmd, **kwargs ) ) - - self.write_line("Tendermint process started\n") + self.log("Tendermint process started\n") def _start_monitoring_thread(self) -> None: """Start a monitoring thread.""" - self._monitoring = StoppableThread(target=self.check_server_status) + self._monitoring = StoppableThread(target=self._monitor_tendermint_process) self._monitoring.start() + def start(self, debug: bool = False) -> None: + """Start a Tendermint node process.""" + self._start_tm_process(debug) + self._start_monitoring_thread() + def _stop_tm_process(self) -> None: """Stop a Tendermint node process.""" - if self._process is None: + if self._process is None or self._stopping: return + self._stopping = True if platform.system() == "Windows": os.kill(self._process.pid, signal.CTRL_C_EVENT) # type: ignore # pylint: disable=no-member + if self._process is None: + return try: self._process.wait(timeout=5) except subprocess.TimeoutExpired: # nosec @@ -217,13 +252,16 @@ def _stop_tm_process(self) -> None: else: self._process.send_signal(signal.SIGTERM) self._process.wait(timeout=5) + if self._process is None: + return poll = self._process.poll() if poll is None: # pragma: nocover self._process.terminate() self._process.wait(3) + self._stopping = False self._process = None - self.write_line("Tendermint process stopped\n") + self.log("Tendermint process stopped\n") def _stop_monitoring_thread(self) -> None: """Stop a monitoring process.""" @@ -233,8 +271,25 @@ def _stop_monitoring_thread(self) -> None: def stop(self) -> None: """Stop a Tendermint node process.""" - self._stop_monitoring_thread() self._stop_tm_process() + self._stop_monitoring_thread() + + @staticmethod + def _write_to_console(line: str) -> None: + """Write line to console.""" + sys.stdout.write(str(line)) + sys.stdout.flush() + + def _write_to_file(self, line: str) -> None: + """Write line to console.""" + with open(self.log_file, "a", encoding=ENCODING) as file: + file.write(line) + + def log(self, line: str) -> None: + """Open and write a line to the log file.""" + self._write_to_console(line=line) + if self.write_to_log: + self._write_to_file(line=line) def prune_blocks(self) -> int: """Prune blocks from the Tendermint state""" @@ -242,46 +297,6 @@ def prune_blocks(self) -> int: ["tendermint", "--home", str(self.params.home), "unsafe-reset-all"] ) - def write_line(self, line: str) -> None: - """Open and write a line to the log file.""" - with open(self.log_file, "a", encoding=ENCODING) as file: - file.write(line) - - def check_server_status( - self, - ) -> None: - """Check server status.""" - if self._monitoring is None: - raise ValueError("Monitoring is not running") - self.write_line("Monitoring thread started\n") - while True: - try: - if self._monitoring.stopped(): - break # break from the loop immediately. - if self._process is not None and self._process.stdout is not None: - line = self._process.stdout.readline() - self.write_line(line) - for trigger in [ - # this occurs when we lose connection from the tm side - "RPC HTTP server stopped", - # whenever the node is stopped because of a closed connection - # from on any of the tendermint modules (abci, p2p, rpc, etc) - # we restart the node - "Stopping abci.socketClient for error: read message: EOF", - ]: - if line.find(trigger) >= 0: - self._stop_tm_process() - # we can only reach this step if monitoring was activated - # so we make sure that after reset the monitoring continues - monitoring = True - self._start_tm_process(monitoring) - self.write_line( - f"Restarted the HTTP RPC server, as a connection was dropped with message:\n\t\t {line}\n" - ) - except Exception as e: # pylint: disable=broad-except - self.write_line(f"Error!: {str(e)}") - self.write_line("Monitoring thread terminated\n") - def reset_genesis_file( self, genesis_time: str, initial_height: str, period_count: str ) -> None: diff --git a/docs/advanced_reference/commands/autonomy_analyse.md b/docs/advanced_reference/commands/autonomy_analyse.md index 13c92418e7..f9116b9b9f 100644 --- a/docs/advanced_reference/commands/autonomy_analyse.md +++ b/docs/advanced_reference/commands/autonomy_analyse.md @@ -12,7 +12,7 @@ This command verifies that the [`AbciApp` class](../../key_concepts/abci_app_cla ??? example - The docstring corresponding to the [Hello World agent service](../../demos/hello_world_demo.md) is + The docstring corresponding to the [Hello World agent service](https://docs.autonolas.network/demos/hello-world/) is ```python @@ -23,20 +23,20 @@ This command verifies that the [`AbciApp` class](../../key_concepts/abci_app_cla Initial states: {RegistrationRound} Transition states: - 0. RegistrationRound + 1. RegistrationRound - done: 1. - 1. CollectRandomnessRound + 2. CollectRandomnessRound - done: 2. - no majority: 1. - round timeout: 1. - 2. SelectKeeperRound + 3. SelectKeeperRound - done: 3. - no majority: 0. - round timeout: 0. - 3. PrintMessageRound + 4. PrintMessageRound - done: 4. - round timeout: 0. - 4. ResetAndPauseRound + 5. ResetAndPauseRound - done: 1. - no majority: 0. - reset timeout: 0. diff --git a/docs/advanced_reference/commands/autonomy_build-image.md b/docs/advanced_reference/commands/autonomy_build-image.md index 07ca9f41c7..b6e33f8d01 100644 --- a/docs/advanced_reference/commands/autonomy_build-image.md +++ b/docs/advanced_reference/commands/autonomy_build-image.md @@ -15,7 +15,7 @@ where `` is the author name from the local CLI config (specified with `a ## Usage ```bash -autonomy build-image [OPTIONS] [PUBLIC_ID] +autonomy build-image [OPTIONS] [AGENT_PUBLIC_ID] ``` ## Options @@ -23,6 +23,10 @@ autonomy build-image [OPTIONS] [PUBLIC_ID] `--service-dir PATH` : Path to the service directory. +`-e, --extra-dependency DEPENDENCY` + +: Provide extra dependency. + `--version TEXT` : Version tag for the image. @@ -35,6 +39,9 @@ autonomy build-image [OPTIONS] [PUBLIC_ID] `--pull` : Pull the latest dependencies when building the image. +`-f, --dockerfile FILE` +: Specify custom `Dockerfile` for building the agent + `--help` : Show the help message and exit. @@ -84,3 +91,11 @@ autonomy build-image [OPTIONS] [PUBLIC_ID] ``` This will tag the image as `/oar-:dev`. + +* Include extra python packages: + + ```bash + autonomy build-image ... -e open-aea-ledger-flashbots==1.43.0.post2 + ``` + + This will tag the image as `/oar-:`. diff --git a/docs/advanced_reference/commands/autonomy_deploy.md b/docs/advanced_reference/commands/autonomy_deploy.md index ab88187d06..8aedf2cac9 100644 --- a/docs/advanced_reference/commands/autonomy_deploy.md +++ b/docs/advanced_reference/commands/autonomy_deploy.md @@ -2,6 +2,40 @@ Build or run agent service deployments. This command group consists of a number of functionalities for building service deployments, run locally stored service deployments, and run service deployments defined in the on-chain protocol. See the appropriate subcommands for more information. +### Options + +`--env-file FILE` +: File containing environment variable mappings + +### Examples + +If you have an `.env` file in the working directory, `autonomy deploy` will load the `.env` file automatically. If the file is not present in the working directory you can provide the path to the file using `--env-file` flag + +```bash +autonomy deploy --env-file COMMAND [ARGS] +``` + +For loading the environment variables you can use a `json` file as well. While using a `json` file you can either use `json` serialized strings like + +```json title="env.json" +{ + "ALL_PARTICIPANTS": "[\"0x0000000000000000000000000000000000000000\"]" +} +``` + +Or the `json` objects + +```json title="env.json" +{ + "ALL_PARTICIPANTS": ["0x0000000000000000000000000000000000000000"] +} +``` + +The framework will handle both of these cases automatically. + +```bash +autonomy deploy --env-file COMMAND [ARGS] +``` ## `autonomy deploy build` @@ -68,20 +102,46 @@ autonomy deploy build [OPTIONS] [KEYS_FILE] `-p` : Ask for password interactively. -`--password PASSWORD` -: Set password for key encryption/decryption. - `--help` : Show the help message and exit. ### Examples + ```bash autonomy deploy build keys.json -ltm ``` Builds a service deployment using the keys stored in the file `keys.json` and applying environment variables to the service configuration file. The deployment will be generated by default for as many agents as keys are stored in `keys.json`. By default, the command searches for the file `keys.json`, if no file name is provided. +### Private key security + +When building deployments, you can use password protected privates keys (eg. generated using `autonomy generate-key LEDGER --password PASSWORD`) to avoid exposing them. + +#### Docker Compose + +In a `docker-compose` deployment you can just export `OPEN_AUTONOMY_PRIVATE_KEY_PASSWORD` environment variable before running the deployment like + +```bash +export OPEN_AUTONOMY_PRIVATE_KEY_PASSWORD=PASSWORD +autonomy deploy run --build-dir PATH_TO_BUILD_DIR +``` + +or + +```bash +export OPEN_AUTONOMY_PRIVATE_KEY_PASSWORD=PASSWORD +docker-compose -f PATH_TO_BUILD_DIR/docker-compose.yaml up +``` + +#### Kubernetes + +In a `kubernetes` deployment, you'll have to export the `OPEN_AUTONOMY_PRIVATE_KEY_PASSWORD` variable when building the deployment, not when running. + +```bash +export OPEN_AUTONOMY_PRIVATE_KEY_PASSWORD=PASSWORD +autonomy deploy build (...) +``` ## `autonomy deploy run` @@ -106,22 +166,32 @@ autonomy deploy run [OPTIONS] `--remove-orphans` : Remove containers for services not defined in the Compose file. +`--detach` +: Run service in the background. + `--help` : Show the help message and exit. ### Examples + ```bash autonomy deploy run --build-dir ./abci_build ``` Runs the service deployment stored locally in the directory `./abci_build`. +To provide password for the private keys + +```bash +export OPEN_AUTONOMY_PRIVATE_KEY_PASSWORD=PASSWORD +autonomy deploy run --build-dir ./abci_build +``` ## `autonomy deploy from-token` Run a service deployment minted on-chain protocol. -This command allows to deploy services directly without having the need to explicitly fetch them locally (also known as "one-click deployment"). The command requires the `TOKEN_ID` which can be checked in the {{on_chain_frontend}}. See the [mint a service on-chain](../../guides/publish_mint_packages.md) guide for more information. +This command allows to deploy services directly without having the need to explicitly fetch them locally (also known as "one-click deployment"). The command requires the `TOKEN_ID` which can be checked in the {{ autonolas_protocol_registry_dapp }}. See the [mint a service on-chain](../../guides/publish_mint_packages.md) guide for more information. To understand how to use various chain profiles refer to `Chain Selection` section on the `autonomy mint` command documentation. @@ -174,3 +244,22 @@ autonomy deploy from-token --use-goerli 2 keys.json ``` Runs the service deployment registered with `TOKEN_ID`=2 in the Görli on-chain protocol. The deployment will be run for as many agents as keys are defined in the `keys.json` file. + + +## `autonomy deploy stop` + +Stop a deployment running in background, if you use `--detach` flag on `autonomy deploy run` or `autonomy deploy from-token` the service will run in background. You can stop this service using `autonomy deploy stop` command. + +### Usage + +```bash +autonomy deploy stop --build-dir BUILD_DIR +``` + +### Options: + +`--build-dir PATH` +: Path to the deployment build directory. + +`--help` +: Show this message and exit. diff --git a/docs/advanced_reference/commands/autonomy_fetch.md b/docs/advanced_reference/commands/autonomy_fetch.md index bf28aa6f1b..cb6c3d3c2c 100644 --- a/docs/advanced_reference/commands/autonomy_fetch.md +++ b/docs/advanced_reference/commands/autonomy_fetch.md @@ -55,5 +55,5 @@ autonomy --registry-path=./packages fetch valory/hello_world:0.1.0 --service --l Fetch the agent service `hello_world` from a remote registry ([IPFS](https://ipfs.io)): ```bash -autonomy fetch valory/hello_world:0.1.0:bafybeigtaxh5zfg32cypqkjvftreivh22sqlrbgw5x3lxjmrf3dyqcioyy --service --remote +autonomy fetch valory/hello_world:0.1.0:bafybeicehljk5ahlsy62t6a5by46uz3nguuxuh653mzoz4hfme22s6eodi --service --remote ``` diff --git a/docs/advanced_reference/commands/autonomy_mint.md b/docs/advanced_reference/commands/autonomy_mint.md index 1ad80f7151..0cd67b654e 100644 --- a/docs/advanced_reference/commands/autonomy_mint.md +++ b/docs/advanced_reference/commands/autonomy_mint.md @@ -1,6 +1,6 @@ -Tools for minting software packages in the [Autonolas Protocol](https://docs.autonolas.network/protocol/). +Tools for minting software packages in the {{ autonolas_protocol }}. -This command group consists of a number of functionalities to mint components, agents and services in the [Autonolas Protocol](https://docs.autonolas.network/protocol/). These commands are the CLI alternative to mint packages using the [Autonolas Protocol web app](https://protocol.autonolas.network/). See the appropriate subcommands for more information. +This command group consists of a number of functionalities to mint components, agents and services in the {{ autonolas_protocol }}. These commands are the CLI alternative to mint packages using the {{ autonolas_protocol_registry_dapp }}. See the appropriate subcommands for more information. !!! info @@ -8,6 +8,9 @@ This command group consists of a number of functionalities to mint components, a ## Options +`--dry-run` +: Perform a dry run for the transaction. + `--use-ethereum` : Use the Ethereum chain profile to interact with the Autonolas Protocol registry contracts. This option requires that you define the following environment variable: @@ -19,17 +22,27 @@ This command group consists of a number of functionalities to mint components, a - `GOERLI_CHAIN_RPC` : RPC endpoint for the Görli testnet chain. `--use-custom-chain` -: Use the custom-chain chain profile to interact with the Autonolas Protocol registry contracts. This option requires that you define the following environment variables (see the [Autonolas Protocol](https://docs.autonolas.network/protocol/) documentation for more information): +: Use the custom-chain profile to interact with the Autonolas Protocol registry contracts. This profile requires that you define some parameters and [contract addresses](../on_chain_addresses.md) as environment variables (see also the {{ autonolas_protocol }} documentation for more information): - `CUSTOM_CHAIN_RPC` : RPC endpoint for the custom chain. - `CUSTOM_CHAIN_ID` : chain ID. - - `CUSTOM_COMPONENT_REGISTRY_ADDRESS` : custom Component Registry - contract address. - - `CUSTOM_AGENT_REGISTRY_ADDRESS` : custom Agent Registry contract address. - - `CUSTOM_REGISTRIES_MANAGER_ADDRESS` : custom Registries Manager contract address. - - `CUSTOM_SERVICE_MANAGER_ADDRESS` : custom Service Manager contract address. - - `CUSTOM_SERVICE_REGISTRY_ADDRESS` : custom Service Registry contract address. - - `CUSTOM_GNOSIS_SAFE_MULTISIG_ADDRESS` : custom Gnosis Safe multisig contract address. + - `CUSTOM_COMPONENT_REGISTRY_ADDRESS` : Custom Component Registry contract address. + - `CUSTOM_AGENT_REGISTRY_ADDRESS` : Custom Agent Registry contract address. + - `CUSTOM_REGISTRIES_MANAGER_ADDRESS` : Custom Registries Manager contract address. + - `CUSTOM_SERVICE_MANAGER_ADDRESS` : Custom Service Manager contract address. + - `CUSTOM_SERVICE_REGISTRY_ADDRESS` : Custom Service Registry contract address. + - `CUSTOM_GNOSIS_SAFE_PROXY_FACTORY_ADDRESS` : Custom Gnosis Safe multisig contract address. + - `CUSTOM_GNOSIS_SAFE_SAME_ADDRESS_MULTISIG_ADDRESS` : Custom Gnosis Safe Same Address Multisig address. + - `CUSTOM_SERVICE_REGISTRY_TOKEN_UTILITY_ADDRESS` : Custom Service Registry Token Utility address. + - `CUSTOM_MULTISEND_ADDRESS` : Custom Multisend address. + +!!! note + For L2 chains you are only required to set + - `CUSTOM_SERVICE_MANAGER_ADDRESS`, + - `CUSTOM_SERVICE_REGISTRY_ADDRESS`, + - `CUSTOM_GNOSIS_SAFE_PROXY_FACTORY_ADDRESS`, + - `CUSTOM_GNOSIS_SAFE_SAME_ADDRESS_MULTISIG_ADDRESS` and + - `CUSTOM_MULTISEND_ADDRESS`. `--use-local` : Use the local chain profile to interact with the Autonolas Protocol registry contracts. This option requires that you have a local Hardhat node with the required contracts deployed. @@ -39,13 +52,19 @@ This command group consists of a number of functionalities to mint components, a The options `--use-ethereum`, `--use-goerli`, `--use-custom-chain` and `--use-local` are mutually exclusive. `-t, --timeout FLOAT` -: Timeout for verifying emitted events +: Timeout for on-chain interactions -`-s, --skip-hash-check` -: Skip hash check when verifying dependencies on chain +`-r, --retries INTEGER` +: Max retries for on-chain interactions -`-l, --latest-dependencies` -: Use latest on-chain dependencies if there are multiple dependencies with same package ID +`--sleep FLOAT` +: Sleep period between retries + +`--skip-hash-check` +: Skip hash check when verifying dependencies on chain. + +`--skip-dependencies-check` +: Skip dependency verification. ## `autonomy mint protocol` / `contract` / `connection` / `skill` @@ -70,50 +89,65 @@ autonomy mint skill [OPTIONS] PACKAGE_PATH `--password PASSWORD` : Password for the key file. +`-d, --dependencies DEPENDENCY_ID` +: Dependencies for the package. + `--nft IPFS_HASH_OR_IMAGE_PATH` : IPFS hash or path to the image for the NFT representing the package. Note that if you are using a local chain this option is not required. `--owner OWNER_ADDRESS` : Owner address of the package. +`--update TOKEN_ID` +: Update the existing minted token with the latest package hash. + ### Examples -Mint the `abstract_abci` skill on a local chain: +Mint the `abstract_abci` skill with dependency IDs 35 and 42 in a local chain: ```bash -autonomy mint skill --key my_key.txt --nft --owner ./packages/valory/skills/abstract_abci +autonomy mint --use-local skill --key my_key.txt --nft --owner -d 35 -d 42 ./packages/valory/skills/abstract_abci ``` Same as above, but using a hardware wallet: ```bash -autonomy mint skill --hwi --nft --owner ./packages/valory/skills/abstract_abci -``` - -When minting the components the open-autonomy framework uses a `subgraph` for resolving dependencies to their respective on-chain token IDs. If a dependency is not minted you'll get the following error - -``` -Error: No on chain registration found for following dependencies - - (PACKAGE_TYPE, AUTHOR/NAME:VERSION:PACKAGE_HASH) +autonomy mint --use-local skill --hwi --nft --owner -d 35 -d 42 ./packages/valory/skills/abstract_abci ``` -The dependency checker uses hashes for resolving token IDs but if you want to use the public IDs to resolve you can use `--skip-hash-check` or `-s` flag on the `autonomy mint` command +Update the minted `abstract_abci` skill using ```bash -autonomy mint --skip-hash-check skill --hwi --nft --owner ./packages/valory/skills/abstract_abci +autonomy mint --use-local skill --key my_key.txt --nft --owner -d 35 -d 42 ./packages/valory/skills/abstract_abci --update ``` -When using public ID for resolving token IDs you might get prompted to select between token IDS since a package can be minted multiple times with different versions. The prompt will look like this +Perform a dry run -``` -Multiple dependencies found for of type -Please choose which dependency to use (token_id_0, token_id_1, ...): +```bash +autonomy mint --dry-run protocol ./packages/valory/protocols/abci --key key.txt ``` -You can avoid the prompts and just use the latest dependencies by using `-l, --latest-dependencies` flag +Output ```bash -autonomy mint --skip-hash-check --latest-dependencies skill --hwi --nft --owner ./packages/valory/skills/abstract_abci +=== Dry run output === +Method: RegistriesManagerContract.get_create_transaction +Contract: 0x... +Kwargs: + owner: 0x... + component_type: UnitType.COMPONENT + metadata_hash: 0x... + sender: 0x... + dependencies: [] +Transaction: + chainId: 31337 + nonce: 0 + value: 0 + gas: 16000 + maxFeePerGas: 4000000000 + maxPriorityFeePerGas: 3000000000 + to: 0x... + data: 0x... ``` ## `autonomy mint agent` @@ -136,24 +170,30 @@ autonomy mint agent [OPTIONS] PACKAGE_PATH `--password PASSWORD` : Password for the key file. +`-d, --dependencies DEPENDENCY_ID` +: Dependencies for the package. In order to be minted, agent packages require at least one dependency. + `--nft NFT_HASH_OR_IMAGE_PATH` : IPFS hash or path to the image for the NFT representing the package. Note that if you are using a local chain this option is not required. `--owner OWNER_ADDRESS` : Owner address of the package. +`--update TOKEN_ID` +: Update the already minted agent with on-chain `TOKEN_ID` with the current package hash. + ### Examples -Mint the `hello_world` agent on the Ethereum mainnet: +Mint the `hello_world` agent with dependency IDs 34, 35, 38, 39, 42, 43, 44, 45, 46, 47, 48 and 49 in the Ethereum main chain: ```bash -autonomy mint --use-ethereum agent --key my_key.txt --nft --owner ./packages/valory/agents/hello_world +autonomy mint --use-ethereum agent --key my_key.txt --nft --owner -d 34 -d 35 -d 38 -d 39 -d 42 -d 43 -d 44 -d 45 -d 46 -d 47 -d 48 -d 49 ./packages/valory/agents/hello_world ``` Same as above, but using a hardware wallet: ```bash -autonomy mint --use-ethereum agent --hwi --nft --owner ./packages/valory/agents/hello_world +autonomy mint --use-ethereum agent --hwi --nft --owner -d 34 -d 35 -d 38 -d 39 -d 42 -d 43 -d 44 -d 45 -d 46 -d 47 -d 48 -d 49 ./packages/valory/agents/hello_world ``` ## `autonomy mint service` @@ -194,6 +234,12 @@ autonomy mint service [OPTIONS] PACKAGE_PATH `--threshold` : Threshold for the minimum number of agents required to run the service. The threshold has to be at least $\lceil(2N + 1) / 3\rceil$, where $N$ is total number of the agents in the service. +`--token ERC20_TOKEN_ADDRESS` +: ERC20 token for securing the service. + +`--update TOKEN_ID` +: Update the already minted service with on-chain `TOKEN_ID` with the current package hash. + ### Examples Mint the `hello_world` service with 4 instances of canonical agent ID 3, cost of bond 10000000000000000 Wei per agent and a threshold of 3 agents, in the Ethereum main chain: @@ -211,3 +257,14 @@ autonomy mint --use-ethereum service --hwi --nft - !!! note You can specify more than one type of canonical agent in a service by appropriately defining the triplets `--agent-id`, `--number-of-slots` and `--cost-of-bond` for each canonical agent ID. + + +You can also use a custom ERC20 token as token to secure the service. Use the `--token` flag to provide the address of the token of your choice: + +```bash +autonomy mint --use-ethereum service --key my_key.txt --nft --owner --agent-id 3 --number-of-slots 4 --cost-of-bond 10000000000000000 --threshold 3 ./packages/valory/services/hello_world --token +``` + +!!! warning "Important" + + If you have minted a service using a custom ERC20 token, then you have to use the same token activate the service and to register the agent instances. \ No newline at end of file diff --git a/docs/advanced_reference/commands/autonomy_service.md b/docs/advanced_reference/commands/autonomy_service.md index 102b60064f..08b50cd2b5 100644 --- a/docs/advanced_reference/commands/autonomy_service.md +++ b/docs/advanced_reference/commands/autonomy_service.md @@ -1,6 +1,6 @@ -Tools to manage services minted in the [Autonolas Protocol](https://docs.autonolas.network/protocol/). +Tools to manage services minted in the {{ autonolas_protocol }}. -This command group consists of a number of functionalities to manage the life cycle of services that have been minted in the [Autonolas Protocol](https://docs.autonolas.network/protocol/). +This command group consists of a number of functionalities to manage [the life cycle of services](https://docs.autonolas.network/protocol/life_cycle_of_a_service/) that have been minted in the {{ autonolas_protocol }}. !!! info @@ -8,6 +8,9 @@ This command group consists of a number of functionalities to manage the life cy ## Options +`--dry-run` +: Perform a dry run for the transaction. + `--use-ethereum` : Use the Ethereum chain profile to interact with the Autonolas Protocol registry contracts. This option requires that you define the following environment variable: @@ -19,17 +22,27 @@ This command group consists of a number of functionalities to manage the life cy - `GOERLI_CHAIN_RPC` : RPC endpoint for the Görli testnet chain. `--use-custom-chain` -: Use the custom-chain chain profile to interact with the Autonolas Protocol registry contracts. This option requires that you define the following environment variables (see the [Autonolas Protocol](https://docs.autonolas.network/protocol/) documentation for more information): +: Use the custom-chain profile to interact with the Autonolas Protocol registry contracts. This profile requires that you define some parameters and [contract addresses](../on_chain_addresses.md) as environment variables (see also the {{ autonolas_protocol }} documentation for more information): - `CUSTOM_CHAIN_RPC` : RPC endpoint for the custom chain. - - `CUSTOM_CHAIN_ID` : Chain ID. - - `CUSTOM_COMPONENT_REGISTRY_ADDRESS` : custom Component Registry - contract address. - - `CUSTOM_AGENT_REGISTRY_ADDRESS` : custom Agent Registry contract address. - - `CUSTOM_REGISTRIES_MANAGER_ADDRESS` : custom Registries Manager contract address. - - `CUSTOM_SERVICE_MANAGER_ADDRESS` : custom Service Manager contract address. - - `CUSTOM_SERVICE_REGISTRY_ADDRESS` : custom Service Registry contract address. - - `CUSTOM_GNOSIS_SAFE_MULTISIG_ADDRESS` : custom Gnosis Safe multisig contract address. + - `CUSTOM_CHAIN_ID` : chain ID. + - `CUSTOM_COMPONENT_REGISTRY_ADDRESS` : Custom Component Registry contract address. + - `CUSTOM_AGENT_REGISTRY_ADDRESS` : Custom Agent Registry contract address. + - `CUSTOM_REGISTRIES_MANAGER_ADDRESS` : Custom Registries Manager contract address. + - `CUSTOM_SERVICE_MANAGER_ADDRESS` : Custom Service Manager contract address. + - `CUSTOM_SERVICE_REGISTRY_ADDRESS` : Custom Service Registry contract address. + - `CUSTOM_GNOSIS_SAFE_PROXY_FACTORY_ADDRESS` : Custom Gnosis Safe multisig contract address. + - `CUSTOM_GNOSIS_SAFE_SAME_ADDRESS_MULTISIG_ADDRESS` : Custom Gnosis Safe Same Address Multisig address. + - `CUSTOM_SERVICE_REGISTRY_TOKEN_UTILITY_ADDRESS` : Custom Service Registry Token Utility address. + - `CUSTOM_MULTISEND_ADDRESS` : Custom Multisend address. + +!!! note + For L2 chains you are only required to set + - `CUSTOM_SERVICE_MANAGER_ADDRESS`, + - `CUSTOM_SERVICE_REGISTRY_ADDRESS`, + - `CUSTOM_GNOSIS_SAFE_PROXY_FACTORY_ADDRESS`, + - `CUSTOM_GNOSIS_SAFE_SAME_ADDRESS_MULTISIG_ADDRESS` and + - `CUSTOM_MULTISEND_ADDRESS`. `--use-local` : Use the local chain profile to interact with the Autonolas Protocol registry contracts. This option requires that you have a local Hardhat node with the required contracts deployed. @@ -38,8 +51,53 @@ This command group consists of a number of functionalities to manage the life cy The options `--use-ethereum`, `--use-goerli`, `--use-custom-chain` and `--use-local` are mutually exclusive. -`--skip-hash-check` -: Skip hash check when verifying dependencies on chain. +`-t, --timeout FLOAT` +: Timeout for on-chain interactions + +`-r, --retries INTEGER` +: Max retries for on-chain interactions + +`--sleep FLOAT` +: Sleep period between retries + +## `autonomy service info` + +Print service information. + +### Usage + +```bash +autonomy service info SERVICE_ID +``` + +### Examples + +```bash +$ autonomy service info 3 + ++---------------------------+----------------------------------------------+ +| Property | Value | ++===========================+==============================================+ +| Service State | DEPLOYED | ++---------------------------+----------------------------------------------+ +| Security Deposit | 1000 | ++---------------------------+----------------------------------------------+ +| Multisig Address | 0x0000000000000000000000000000000000000000 | ++---------------------------+----------------------------------------------+ +| Cannonical Agents | 1 | ++---------------------------+----------------------------------------------+ +| Max Agents | 4 | ++---------------------------+----------------------------------------------+ +| Threshold | 3 | ++---------------------------+----------------------------------------------+ +| Number Of Agent Instances | 4 | ++---------------------------+----------------------------------------------+ +| Registered Instances | - 0x0000000000000000000000000000000000000000 | +| | - 0x0000000000000000000000000000000000000000 | +| | - 0x0000000000000000000000000000000000000000 | +| | - 0x0000000000000000000000000000000000000000 | ++---------------------------+----------------------------------------------+ +``` ## `autonomy service activate` @@ -59,6 +117,9 @@ autonomy service activate [OPTIONS] SERVICE_ID `--hwi` : Use a hardware wallet to sign the transactions. +`--token ERC20_TOKEN_ADDRESS` +: ERC20 token to use for activating the service. You must specify the same token used when minting the service. See the [`autonomy mint service`](./autonomy_mint.md#autonomy-mint-service) command. + `--password PASSWORD` : Password for the key file. @@ -72,13 +133,22 @@ autonomy service activate 42 --key my_key.txt Same as above, but using a hardware wallet: -``bash +```bash autonomy service activate 42 --hwi ``` +If an ERC20 token was used as bonding token when the service was minted, then you have to provide the same token address using the `--token` flag: + +```bash +autonomy service activate 42 --key my_key.txt --token +``` + +Make sure your account holds enough funds for activating the service: + ## `autonomy service register` Register an agent instance in a service minted and activated in the Autonolas Protocol. + ### Usage ```bash @@ -99,6 +169,9 @@ autonomy service register [OPTIONS] SERVICE_ID `-a, --agent-id AGENT_ID` : Canonical agent ID. +`--token ERC20_TOKEN_ADDRESS` +: ERC20 token to use as bond for the agent instances. You must specify the same token used when minting the service. See the [`autonomy mint service`](./autonomy_mint.md#autonomy-mint-service) command. + `--password PASSWORD` : Password for the key file. @@ -118,6 +191,14 @@ autonomy service register -i 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 -a 56 42 When providing the agent instance address make sure that the address you provide is funded. +If an ERC20 token was used as bonding token when the service was minted, then you have to provide the same token address using the `--token` flag: + +```bash +autonomy service register -i 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 -a 56 42 --hwi --token +``` + +Make sure your account holds enough funds to pay for the agent bonds. + ## `autonomy service deploy` Deploy a service in the Autonolas Protocol. @@ -131,14 +212,17 @@ autonomy service deploy [OPTIONS] SERVICE_ID ``` ### Options +`--reuse-multisig` +: Reuse `mutlisig` from previous deployment. + `--key FILE` : Use a private key from a file to sign the transactions. `--hwi` : Use a hardware wallet to sign the transactions. -`-d, --deployment-payload PAYLOAD` -: Deployment payload value. +`-f, --fallback-handler ADDRESS` +: Fallback handler address for the gnosis safe multisig. `--password PASSWORD` : Password for the key file. @@ -155,4 +239,76 @@ Same as above, but using a hardware wallet: ```bash autonomy service deploy 42 --hwi -``` \ No newline at end of file +``` + +## `autonomy service terminate` + +Terminate a service. + +This command can be executed after the service is activated. + +### Usage + +```bash +autonomy service terminate [OPTIONS] SERVICE_ID +``` +### Options + +`--key FILE` +: Use a private key from a file to sign the transactions. + +`--hwi` +: Use a hardware wallet to sign the transactions. + +`--password PASSWORD` +: Password for the key file. + +### Examples + +To terminate the service with ID 42 in the Autonolas Protocol: + +```bash +autonomy service terminate 42 --key my_key.txt +``` + +Same as above, but using a hardware wallet: + +```bash +autonomy service terminate 42 --hwi +``` + +## `autonomy service unbond` + +Unbond a service. + +This command can be executed after the service is terminated. + +### Usage + +```bash +autonomy service unbond [OPTIONS] SERVICE_ID +``` +### Options + +`--key FILE` +: Use a private key from a file to sign the transactions. + +`--hwi` +: Use a hardware wallet to sign the transactions. + +`--password PASSWORD` +: Password for the key file. + +### Examples + +To unbond a service with ID 42 in the Autonolas Protocol: + +```bash +autonomy service unbond 42 --key my_key.txt +``` + +Same as above, but using a hardware wallet: + +```bash +autonomy service unbond 42 --hwi +``` diff --git a/docs/advanced_reference/developer_tooling/benchmarking.md b/docs/advanced_reference/developer_tooling/benchmarking.md index 3b20d53f55..1e36a75103 100644 --- a/docs/advanced_reference/developer_tooling/benchmarking.md +++ b/docs/advanced_reference/developer_tooling/benchmarking.md @@ -31,7 +31,8 @@ To set up the tool, you need to follow a couple of steps detailed below. Note th 2. Ensure that the skill configuration file `skill.yaml` points correctly to the skill benchmark tool in the section `models`. - ```yaml + ```yaml title="skill.yaml" + # (...) models: benchmark_tool: args: @@ -91,7 +92,7 @@ The benchmark data will be stored in the folder `/abci_build/per ## Use the command line to aggregate benchmark information -1. **Run the service.** Build and run the agent service in [dev mode](./dev_mode.md#build-and-run-an-agent-service-in-dev-mode). (The tool also works if you run the agent [normal mode](../../guides/deploy_service.md#local-deployment).) +1. **Run the service.** Build and run the agent service in [dev mode](./dev_mode.md#build-and-run-an-agent-service-in-dev-mode). (The tool also works if you run the agent [normal mode](../../guides/deploy_service.md#local-deployment-full-workflow).) 2. **Wait for service execution.** Wait until the service has completed at least one period before cancelling the execution. That is, wait until the `ResetAndPauseRound` round has occurred at least once. As commented above, this is required because benchmark data is saved in this state. Once you have a data dump, you can stop the local execution by pressing `Ctrl-C`. diff --git a/docs/advanced_reference/developer_tooling/custom_agent_image.md b/docs/advanced_reference/developer_tooling/custom_agent_image.md new file mode 100644 index 0000000000..c31d37f4e1 --- /dev/null +++ b/docs/advanced_reference/developer_tooling/custom_agent_image.md @@ -0,0 +1,29 @@ +When building the agent images, you might run into a situation where an agent dependency requires a third party developer library which can lead to the image build failing. In such cases you can use a custom `Dockerfile` with a layer which installs this third party library. Use following template to define the `Dockerfile` + +```dockerfile +ARG AUTONOMY_IMAGE_VERSION="latest" +ARG AUTONOMY_IMAGE_NAME="valory/open-autonomy" +FROM ${AUTONOMY_IMAGE_NAME}:${AUTONOMY_IMAGE_VERSION} + +ARG AEA_AGENT +ARG AUTHOR +ARG EXTRA_DEPENDENCIES + +RUN aea init --reset --remote --ipfs --author ${AUTHOR} + +WORKDIR /root + +# Install the third party libraries here + +RUN AEA_AGENT=${AEA_AGENT} EXTRA_DEPENDENCIES=${EXTRA_DEPENDENCIES} bash /root/scripts/install.sh + +CMD ["/root/scripts/start.sh"] + +HEALTHCHECK --interval=3s --timeout=600s --retries=600 CMD netstat -ltn | grep -c 26658 > /dev/null; if [ 0 != $? ]; then exit 1; fi; +``` + +When building the image use, `--dockerfile` flag to point to this custom `Dockerfile` + +```bash +$ autonomy build-image --dockerfile DOCKERFILE_PATH +``` \ No newline at end of file diff --git a/docs/advanced_reference/developer_tooling/debugging_in_the_cluster.md b/docs/advanced_reference/developer_tooling/debugging_in_the_cluster.md index 032c037525..bf0c5c5cde 100644 --- a/docs/advanced_reference/developer_tooling/debugging_in_the_cluster.md +++ b/docs/advanced_reference/developer_tooling/debugging_in_the_cluster.md @@ -22,7 +22,8 @@ docker image push Finally, build the deployment and run it: ```bash -autonomy deploy build ../generated_keys.json --password ${PASSWORD} --kubernetes --dev +export OPEN_AUTONOMY_PRIVATE_KEY_PASSWORD=${PASSWORD} +autonomy deploy build ../generated_keys.json --kubernetes --dev kubectl apply -f abci_build/ kubectl apply -f abci_build/agent_keys ``` diff --git a/docs/debugging.md b/docs/advanced_reference/developer_tooling/debugging_using_tenderly.md similarity index 100% rename from docs/debugging.md rename to docs/advanced_reference/developer_tooling/debugging_using_tenderly.md diff --git a/docs/advanced_reference/developer_tooling/dev_mode.md b/docs/advanced_reference/developer_tooling/dev_mode.md index 470df3c64e..03967e0625 100644 --- a/docs/advanced_reference/developer_tooling/dev_mode.md +++ b/docs/advanced_reference/developer_tooling/dev_mode.md @@ -93,8 +93,8 @@ By default the command that builds the service deployment (`autonomy deploy buil The deployment setup will include a Hardhat node (image `valory/open-autonomy-hardhat`) using `hardhat` as container name. Therefore, in order to use this node, you must set a [service-level override](../../configure_service/service_configuration_file.md#service-level-overrides) so that the `valory/ledger` connection address is set to `http://hardhat:8545`. You can achieve this by editing the service configuration file `service.yaml` as follows: -```yaml -(...) +```yaml title="service.yaml" +# (...) --- public_id: valory/ledger:0.1.0 type: connection @@ -106,8 +106,8 @@ config: Alternatively, you can leave the default `service.yaml` and export an environment variable: -```yaml -(...) +```yaml title="service.yaml" +# (...) --- public_id: valory/ledger:0.1.0 type: connection @@ -130,8 +130,8 @@ You can also include an ACN node for agent communication using the `--use-acn` f The deployment setup will include an ACN node (image `valory/open-acn-node`) using `acn` as container name. Similarly as above, in order to use this node you must set a [service-level override](../../configure_service/service_configuration_file.md#service-level-overrides) so that the `valory/p2p_libp2p_client` connection parameters are set to the appropriate values. You can achieve this by editing the service configuration file `service.yaml` as follows: -```yaml -(...) +```yaml title="service.yaml" +# (...) --- public_id: valory/p2p_libp2p_client:0.1.0 type: connection diff --git a/docs/advanced_reference/on_chain_addresses.md b/docs/advanced_reference/on_chain_addresses.md new file mode 100644 index 0000000000..5f2d1d8a7d --- /dev/null +++ b/docs/advanced_reference/on_chain_addresses.md @@ -0,0 +1,39 @@ +# List of contract addresses + +## Polygon (137) +| Name | Environment Variable | Address | +| ---- | -------------------- | ------- | +| `Service Registry L 2` | `CUSTOM_SERVICE_REGISTRY_ADDRESS` | [`0xE3607b00E75f6405248323A9417ff6b39B244b50`](https://polygonscan.com/address/0xE3607b00E75f6405248323A9417ff6b39B244b50) | +| `Service Manager` | `CUSTOM_SERVICE_MANAGER_ADDRESS` | [`0x3C1fF68f5aa342D296d4DEe4Bb1cACCA912D95fE`](https://polygonscan.com/address/0x3C1fF68f5aa342D296d4DEe4Bb1cACCA912D95fE) | +| `Gnosis Safe Multisig` | `CUSTOM_GNOSIS_SAFE_PROXY_FACTORY_ADDRESS` | [`0x3d77596beb0f130a4415df3D2D8232B3d3D31e44`](https://polygonscan.com/address/0x3d77596beb0f130a4415df3D2D8232B3d3D31e44) | +| `Gnosis Safe Same Address Multisig` | `CUSTOM_GNOSIS_SAFE_SAME_ADDRESS_MULTISIG_ADDRESS` | [`0xd8BCC126ff31d2582018715d5291A508530587b0`](https://polygonscan.com/address/0xd8BCC126ff31d2582018715d5291A508530587b0) | +| `Multisend` | `CUSTOM_MULTISEND_ADDRESS` | [`0x40A2aCCbd92BCA938b02010E17A5b8929b49130D`](https://polygonscan.com/address/0x40A2aCCbd92BCA938b02010E17A5b8929b49130D) | + +## Polygon Mumbai (80001) +| Name | Environment Variable | Address | +| ---- | -------------------- | ------- | +| `Service Registry L 2` | `CUSTOM_SERVICE_REGISTRY_ADDRESS` | [`0xf805DfF246CC208CD2F08ffaD242b7C32bc93623`](https://mumbai.polygonscan.com/address/0xf805DfF246CC208CD2F08ffaD242b7C32bc93623) | +| `Service Manager` | `CUSTOM_SERVICE_MANAGER_ADDRESS` | [`0x43d28764bB39936185c84906983fB57A8A905a4F`](https://mumbai.polygonscan.com/address/0x43d28764bB39936185c84906983fB57A8A905a4F) | +| `Gnosis Safe Multisig` | `CUSTOM_GNOSIS_SAFE_PROXY_FACTORY_ADDRESS` | [`0x9dEc6B62c197268242A768dc3b153AE7a2701396`](https://mumbai.polygonscan.com/address/0x9dEc6B62c197268242A768dc3b153AE7a2701396) | +| `Gnosis Safe Same Address Multisig` | `CUSTOM_GNOSIS_SAFE_SAME_ADDRESS_MULTISIG_ADDRESS` | [`0xd6AA4Ec948d84f6Db8EEf25104CeE0Ecd280C74e`](https://mumbai.polygonscan.com/address/0xd6AA4Ec948d84f6Db8EEf25104CeE0Ecd280C74e) | +| `Multisend` | `CUSTOM_MULTISEND_ADDRESS` | [`0x40A2aCCbd92BCA938b02010E17A5b8929b49130D`](https://mumbai.polygonscan.com/address/0x40A2aCCbd92BCA938b02010E17A5b8929b49130D) | + +## Gnosis (100) +| Name | Environment Variable | Address | +| ---- | -------------------- | ------- | +| `Service Registry L 2` | `CUSTOM_SERVICE_REGISTRY_ADDRESS` | [`0x9338b5153AE39BB89f50468E608eD9d764B755fD`](https://gnosisscan.io/address/0x9338b5153AE39BB89f50468E608eD9d764B755fD) | +| `Service Registry Token Utility` | `CUSTOM_SERVICE_REGISTRY_TOKEN_UTILITY_ADDRESS` | [`0xa45E64d13A30a51b91ae0eb182e88a40e9b18eD8`](https://gnosisscan.io/address/0xa45E64d13A30a51b91ae0eb182e88a40e9b18eD8) | +| `Service Manager Token` | `CUSTOM_SERVICE_MANAGER_ADDRESS` | [`0x04b0007b2aFb398015B76e5f22993a1fddF83644`](https://gnosisscan.io/address/0x04b0007b2aFb398015B76e5f22993a1fddF83644) | +| `Gnosis Safe Multisig` | `CUSTOM_GNOSIS_SAFE_PROXY_FACTORY_ADDRESS` | [`0x3C1fF68f5aa342D296d4DEe4Bb1cACCA912D95fE`](https://gnosisscan.io/address/0x3C1fF68f5aa342D296d4DEe4Bb1cACCA912D95fE) | +| `Gnosis Safe Same Address Multisig` | `CUSTOM_GNOSIS_SAFE_SAME_ADDRESS_MULTISIG_ADDRESS` | [`0x6e7f594f680f7aBad18b7a63de50F0FeE47dfD06`](https://gnosisscan.io/address/0x6e7f594f680f7aBad18b7a63de50F0FeE47dfD06) | +| `Multisend` | `CUSTOM_MULTISEND_ADDRESS` | [`0x40A2aCCbd92BCA938b02010E17A5b8929b49130D`](https://gnosisscan.io/address/0x40A2aCCbd92BCA938b02010E17A5b8929b49130D) | + +## Chiado (10200) +| Name | Environment Variable | Address | +| ---- | -------------------- | ------- | +| `Service Registry L 2` | `CUSTOM_SERVICE_REGISTRY_ADDRESS` | [`0x31D3202d8744B16A120117A053459DDFAE93c855`](https://gnosis-chiado.blockscout.com/address/0x31D3202d8744B16A120117A053459DDFAE93c855) | +| `Service Registry Token Utility` | `CUSTOM_SERVICE_REGISTRY_TOKEN_UTILITY_ADDRESS` | [`0xc2c7E40674f1C7Bb99eFe5680Efd79842502bED4`](https://gnosis-chiado.blockscout.com/address/0xc2c7E40674f1C7Bb99eFe5680Efd79842502bED4) | +| `Service Manager Token` | `CUSTOM_SERVICE_MANAGER_ADDRESS` | [`0xc965a32185590Eb5a5fffDba29E96126b7650eDe`](https://gnosis-chiado.blockscout.com/address/0xc965a32185590Eb5a5fffDba29E96126b7650eDe) | +| `Gnosis Safe Multisig` | `CUSTOM_GNOSIS_SAFE_PROXY_FACTORY_ADDRESS` | [`0xeB49bE5DF00F74bd240DE4535DDe6Bc89CEfb994`](https://gnosis-chiado.blockscout.com/address/0xeB49bE5DF00F74bd240DE4535DDe6Bc89CEfb994) | +| `Gnosis Safe Same Address Multisig` | `CUSTOM_GNOSIS_SAFE_SAME_ADDRESS_MULTISIG_ADDRESS` | [`0xE16adc7777B7C2a0d35033bd3504C028AB28EE8b`](https://gnosis-chiado.blockscout.com/address/0xE16adc7777B7C2a0d35033bd3504C028AB28EE8b) | +| `Multisend` | `CUSTOM_MULTISEND_ADDRESS` | [`0x40A2aCCbd92BCA938b02010E17A5b8929b49130D`](https://gnosis-chiado.blockscout.com/address/0x40A2aCCbd92BCA938b02010E17A5b8929b49130D) | diff --git a/docs/api/analyse/benchmark/aggregate.md b/docs/api/analyse/benchmark/aggregate.md index db6696caf6..52045c5c5b 100644 --- a/docs/api/analyse/benchmark/aggregate.md +++ b/docs/api/analyse/benchmark/aggregate.md @@ -19,30 +19,58 @@ Block types. #### read`_`benchmark`_`data ```python -def read_benchmark_data(path: Path) -> List[Dict] +def read_benchmark_data(path: Path, + block_type: str = BlockTypes.ALL, + period: int = -1) -> Dict[str, Dict[str, List[Dict]]] ``` Returns logs. - + -#### create`_`dataframe +#### add`_`statistic ```python -def create_dataframe(data: List[Dict]) -> pd.DataFrame +def add_statistic(name: str, aggregator: Callable, behaviours: List[str], + behaviour_history: Dict[str, List[float]]) -> str ``` -Create pandas.DataFrame object from benchmark data. +Add a stastic column. - + -#### format`_`output +#### add`_`statistics ```python -def format_output(df: pd.DataFrame, period: int, block_type: str) -> str +def add_statistics(behaviours: List[str], + behaviour_history: Dict[str, List[float]]) -> str ``` -Format output from given dataframe and parameters +Add statistics. + + + +#### create`_`table`_`data + +```python +def create_table_data( + data: Dict[str, List[Dict]], + blocks: Tuple[str, + ...]) -> Tuple[List[str], List[str], Dict[str, Dict]] +``` + +Create table data. + + + +#### create`_`agent`_`table + +```python +def create_agent_table(agent: str, data: Dict[str, List[Dict]], + blocks: Tuple[str, ...]) -> str +``` + +Create agent table. diff --git a/docs/api/analyse/logs/collection.md b/docs/api/analyse/logs/collection.md index 7ffb0d43cd..248716c1f0 100644 --- a/docs/api/analyse/logs/collection.md +++ b/docs/api/analyse/logs/collection.md @@ -54,8 +54,9 @@ Create logs database. ```python @staticmethod -def get_next_log_block(fp: TextIO, - prev_line: str) -> Tuple[Optional[str], Optional[str]] +def get_next_log_block( + fp: TextIO, + prev_line: Optional[str]) -> Tuple[Optional[str], Optional[str]] ``` Get next log block. diff --git a/docs/api/analyse/service.md b/docs/api/analyse/service.md index 6b17adfdd0..7efa02e7c1 100644 --- a/docs/api/analyse/service.md +++ b/docs/api/analyse/service.md @@ -4,6 +4,49 @@ Tools for analysing the service for deployment readiness + + +## CustomSchemaValidationError Objects + +```python +class CustomSchemaValidationError(SchemaValidationError) +``` + +Custom schema validation error to report all errors at once. + + + +#### `__`init`__` + +```python +def __init__(extra_properties: Optional[List[str]] = None, + missing_properties: Optional[List[str]] = None, + not_having_enough_properties: Optional[List[str]] = None, + **kwargs: Any) -> None +``` + +Initialize object. + + + +## CustomSchemaValidator Objects + +```python +class CustomSchemaValidator(Draft4Validator) +``` + +Custom schema validator to report all missing fields at once. + + + +#### validate + +```python +def validate(*args: Any, **kwargs: Any) -> None +``` + +Validate and raise all errors at once. + ## ServiceValidationFailed Objects @@ -30,8 +73,10 @@ Tools to analyse a service ```python def __init__(service_config: Service, + abci_skill_id: PublicId, is_on_chain_check: bool = False, - logger: Optional[logging.Logger] = None) -> None + logger: Optional[logging.Logger] = None, + skip_warnings: bool = False) -> None ``` Initialise object. @@ -69,13 +114,47 @@ def cross_verify_overrides(agent_config: AgentConfig, Cross verify overrides between service config and agent config + + +#### validate`_`override`_`env`_`vars + +```python +@classmethod +def validate_override_env_vars( + cls, + overrides: Union[OrderedDict, dict], + validate_env_var_name: bool = False, + json_path: Optional[List[str]] = None) -> List[str] +``` + +Validate environment variables. + + + +#### validate`_`agent`_`override`_`env`_`vars + +```python +def validate_agent_override_env_vars(agent_config: AgentConfig) -> None +``` + +Check if all of the overrides are defined as a env vars in the agent config + + + +#### validate`_`service`_`override`_`env`_`vars + +```python +def validate_service_override_env_vars() -> None +``` + +Check if all of the overrides are defined as a env vars in the agent config + #### validate`_`override ```python -@classmethod -def validate_override(cls, component_id: ComponentId, override: Dict, +def validate_override(component_id: ComponentId, override: Dict, has_multiple_overrides: bool) -> None ``` diff --git a/docs/api/chain/base.md b/docs/api/chain/base.md index 82efa3a7c1..e8cb12ac10 100644 --- a/docs/api/chain/base.md +++ b/docs/api/chain/base.md @@ -44,7 +44,7 @@ On chain registry contracts helper ```python @staticmethod -def get_contract(public_id: PublicId) -> Contract +def get_contract(public_id: PublicId, cache: bool = True) -> Contract ``` Load contract for given public id. @@ -104,3 +104,58 @@ def service_registry() -> Contract Returns an instance of the registries manager contract. + + +#### service`_`registry`_`token`_`utility + +```python +@property +def service_registry_token_utility() -> Contract +``` + +Returns an instance of the service registry token utility contract. + + + +#### erc20 + +```python +@property +def erc20() -> Contract +``` + +Returns an instance of the service registry token utility contract. + + + +#### gnosis`_`safe + +```python +@property +def gnosis_safe() -> Contract +``` + +Returns an instance of the service registry token utility contract. + + + +#### gnosis`_`safe`_`proxy`_`factory + +```python +@property +def gnosis_safe_proxy_factory() -> Contract +``` + +Returns an instance of the service registry token utility contract. + + + +#### multisend + +```python +@property +def multisend() -> Contract +``` + +Returns an instance of the service registry token utility contract. + diff --git a/docs/api/chain/constants.md b/docs/api/chain/constants.md index 0113837cb7..6e6729291a 100644 --- a/docs/api/chain/constants.md +++ b/docs/api/chain/constants.md @@ -4,3 +4,36 @@ Chain constants + + +#### CONTRACTS`_`DIR`_`LOCAL + +use from an editable/local installation + + + +#### ERC20`_`TOKEN`_`ADDRESS`_`LOCAL + +nosec + + + +## ContractAddresses Objects + +```python +@dataclass +class ContractAddresses() +``` + +Contract addresses container for a chain. + + + +#### get + +```python +def get(name: str) -> str +``` + +Returns the contract address. + diff --git a/docs/api/chain/exceptions.md b/docs/api/chain/exceptions.md index c8f6081199..9845f76747 100644 --- a/docs/api/chain/exceptions.md +++ b/docs/api/chain/exceptions.md @@ -14,25 +14,45 @@ class ChainInteractionError(Exception) Base chain interaction failure. - + -## ComponentMintFailed Objects +## RPCError Objects ```python -class ComponentMintFailed(ChainInteractionError) +class RPCError(ChainInteractionError) ``` -Raise when component minting fails. +RPC error. + + + +## TxBuildError Objects + +```python +class TxBuildError(ChainInteractionError) +``` + +Tx build error. + + + +## ChainTimeoutError Objects + +```python +class ChainTimeoutError(ChainInteractionError) +``` + +Timeout error for interecting with chain. - + -## FailedToRetrieveTokenId Objects +## ComponentMintFailed Objects ```python -class FailedToRetrieveTokenId(ChainInteractionError) +class ComponentMintFailed(ChainInteractionError) ``` -Raise when token ID retrieving fails for minted component. +Raise when component minting fails. @@ -94,3 +114,23 @@ class ServiceDeployFailed(ChainInteractionError) Raise when service activation fails. + + +## TerminateServiceFailed Objects + +```python +class TerminateServiceFailed(ChainInteractionError) +``` + +Raise when service termination fails. + + + +## UnbondServiceFailed Objects + +```python +class UnbondServiceFailed(ChainInteractionError) +``` + +Raise when service unbond call fails. + diff --git a/docs/api/chain/mint.md b/docs/api/chain/mint.md index a5e7ccc73e..cbcf3da422 100644 --- a/docs/api/chain/mint.md +++ b/docs/api/chain/mint.md @@ -9,7 +9,12 @@ Helpers for minting components #### transact ```python -def transact(ledger_api: LedgerApi, crypto: Crypto, tx: Dict) -> Dict +def transact(ledger_api: LedgerApi, + crypto: Crypto, + tx: Dict, + max_retries: int = 5, + sleep: float = 5.0, + timeout: Optional[float] = None) -> Dict ``` Make a transaction and return a receipt @@ -26,50 +31,94 @@ def sort_service_dependency_metadata( Sort service dependencies and their respective parameters - + -#### wait`_`for`_`component`_`to`_`mint +## MintManager Objects ```python -def wait_for_component_to_mint(token_retriever: Callable[[], Optional[int]], - timeout: Optional[float] = None, - sleep: float = 1.0) -> int +class MintManager() ``` -Wait for service activation. +Mint helper. - + + +#### `__`init`__` + +```python +def __init__(ledger_api: LedgerApi, + crypto: Crypto, + chain_type: ChainType, + dry_run: bool = False, + timeout: Optional[float] = None, + retries: Optional[int] = None, + sleep: Optional[float] = None) -> None +``` + +Initialize object. + + + +#### validate`_`address + +```python +def validate_address(address: str) -> str +``` + +Validate address string. + + #### mint`_`component ```python -def mint_component(ledger_api: LedgerApi, - crypto: Crypto, - metadata_hash: str, +def mint_component(metadata_hash: str, component_type: UnitType, - chain_type: ChainType, owner: Optional[str] = None, - dependencies: Optional[List[int]] = None, - timeout: Optional[float] = None) -> Optional[int] + dependencies: Optional[List[int]] = None) -> Optional[int] ``` Publish component on-chain. - + + +#### update`_`component + +```python +def update_component(metadata_hash: str, unit_id: int, + component_type: UnitType) -> Optional[int] +``` + +Update component on-chain. + + #### mint`_`service ```python -def mint_service(ledger_api: LedgerApi, - crypto: Crypto, - metadata_hash: str, - chain_type: ChainType, +def mint_service(metadata_hash: str, agent_ids: List[int], number_of_slots_per_agent: List[int], cost_of_bond_per_agent: List[int], threshold: int, - owner: Optional[str] = None, - timeout: Optional[float] = None) -> Optional[int] + token: Optional[str] = None, + owner: Optional[str] = None) -> Optional[int] +``` + +Publish component on-chain. + + + +#### update`_`service + +```python +def update_service(metadata_hash: str, + service_id: int, + agent_ids: List[int], + number_of_slots_per_agent: List[int], + cost_of_bond_per_agent: List[int], + threshold: int, + token: Optional[str] = None) -> Optional[int] ``` Publish component on-chain. diff --git a/docs/api/chain/service.md b/docs/api/chain/service.md index 9087179b8a..4550c0efbc 100644 --- a/docs/api/chain/service.md +++ b/docs/api/chain/service.md @@ -4,6 +4,26 @@ Helper functions to manage on-chain services + + +## MultiSendOperation Objects + +```python +class MultiSendOperation(Enum) +``` + +Operation types. + + + +#### get`_`delployment`_`payload + +```python +def get_delployment_payload(fallback_handler: Optional[str] = None) -> str +``` + +Calculates deployment payload. + #### get`_`agent`_`instances @@ -48,44 +68,113 @@ security deposit, multisig address, IPFS hash for config, threshold, max number of agent instances, number of agent instances, service state, list of cannonical agents - + -#### wait`_`for`_`success`_`event +#### get`_`token`_`deposit`_`amount ```python -def wait_for_success_event(success_check: Callable[[], bool], - message: str = "Timeout error", - timeout: Optional[float] = None, - sleep: float = 1.0) -> None +def get_token_deposit_amount(ledger_api: LedgerApi, + chain_type: ChainType, + service_id: int, + agent_id: Optional[int] = None) -> int ``` -Wait for success event. +Returns service info. - + -#### wait`_`for`_`agent`_`instance`_`registration +#### get`_`activate`_`registration`_`amount ```python -def wait_for_agent_instance_registration( - ledger_api: LedgerApi, - chain_type: ChainType, - service_id: int, - instances: List[str], - timeout: Optional[float] = None) -> None +def get_activate_registration_amount(ledger_api: LedgerApi, + chain_type: ChainType, service_id: int, + agents: List[int]) -> int ``` -Wait for agent instance registration. +Get activate registration amount. + + + +#### is`_`service`_`token`_`secured + +```python +def is_service_token_secured(ledger_api: LedgerApi, chain_type: ChainType, + service_id: int) -> bool +``` + +Check if the service is token secured. + + + +#### approve`_`erc20`_`usage + +```python +def approve_erc20_usage(ledger_api: LedgerApi, + crypto: Crypto, + chain_type: ChainType, + spender: str, + amount: int, + sender: str, + dry_run: bool = False, + timeout: Optional[float] = None, + retries: Optional[int] = None, + sleep: Optional[float] = None) -> None +``` + +Approve ERC20 token usage. + + + +## ServiceManager Objects + +```python +class ServiceManager() +``` + +Service manager. + + + +#### `__`init`__` + +```python +def __init__(ledger_api: LedgerApi, + crypto: Crypto, + chain_type: ChainType, + dry_run: bool = False, + timeout: Optional[float] = None, + retries: Optional[int] = None, + sleep: Optional[float] = None) -> None +``` + +Initialize object. + + + +#### get`_`service`_`info + +```python +def get_service_info(token_id: int) -> ServiceInfo +``` + +Returns service info. + +**Arguments**: + +- `token_id`: Token ID pointing to the on-chain service + +**Returns**: + +security deposit, multisig address, IPFS hash for config, +threshold, max number of agent instances, number of agent instances, +service state, list of cannonical agents - + -#### activate`_`service +#### activate ```python -def activate_service(ledger_api: LedgerApi, - crypto: Crypto, - chain_type: ChainType, - service_id: int, - timeout: Optional[float] = None) -> None +def activate(service_id: int) -> None ``` Activate service. @@ -95,24 +184,15 @@ before you can proceed further. **Arguments**: -- `ledger_api`: `aea.crypto.LedgerApi` object for interacting with the chain -- `crypto`: `aea.crypto.Crypto` object which has a funded key -- `chain_type`: Chain type - `service_id`: Service ID retrieved after minting a service -- `timeout`: Time to wait for activation event to emit - + #### register`_`instance ```python -def register_instance(ledger_api: LedgerApi, - crypto: Crypto, - chain_type: ChainType, - service_id: int, - instances: List[str], - agent_ids: List[int], - timeout: Optional[float] = None) -> None +def register_instance(service_id: int, instances: List[str], + agent_ids: List[int]) -> None ``` Register instance. @@ -127,26 +207,19 @@ and not as same as the service owner. **Arguments**: -- `ledger_api`: `aea.crypto.LedgerApi` object for interacting with the chain -- `crypto`: `aea.crypto.Crypto` object which has a funded key -- `chain_type`: Chain type - `service_id`: Service ID retrieved after minting a service - `instances`: Address of the agent instance - `agent_ids`: Agent ID of the agent that you want this instance to be a part of when deployed -- `timeout`: Time to wait for register instance event to emit - + -#### deploy`_`service +#### deploy ```python -def deploy_service(ledger_api: LedgerApi, - crypto: Crypto, - chain_type: ChainType, - service_id: int, - deployment_payload: Optional[str] = None, - timeout: Optional[float] = None) -> None +def deploy(service_id: int, + fallback_handler: Optional[str] = None, + reuse_multisig: bool = False) -> None ``` Deploy service. @@ -156,11 +229,53 @@ the service and registered the required agent instances. **Arguments**: -- `ledger_api`: `aea.crypto.LedgerApi` object for interacting with the chain -- `crypto`: `aea.crypto.Crypto` object which has a funded key -- `chain_type`: Chain type - `service_id`: Service ID retrieved after minting a service -- `deployment_payload`: Deployment payload to include when making the -deployment transaction -- `timeout`: Time to wait for deploy event to emit +- `fallback_handler`: Fallback handler address for gnosis safe multisig +- `reuse_multisig`: Use multisig from the previous deployment + + + +#### terminate + +```python +def terminate(service_id: int) -> None +``` + +Terminate service. + +Using this method you can terminate a service on-chain once you have activated +the service and registered the required agent instances. + +**Arguments**: + +- `service_id`: Service ID retrieved after minting a service + + + +#### unbond + +```python +def unbond(service_id: int) -> None +``` + +Unbond service. + +Using this method you can unbond a service on-chain once you have terminated +the service. + +**Arguments**: + +- `service_id`: Service ID retrieved after minting a service + + + +#### get`_`reuse`_`multisig`_`payload + +```python +def get_reuse_multisig_payload( + ledger_api: LedgerApi, crypto: Crypto, chain_type: ChainType, + service_id: int) -> Tuple[Optional[str], Optional[str]] +``` + +Reuse multisig. diff --git a/docs/api/chain/tx.md b/docs/api/chain/tx.md new file mode 100644 index 0000000000..6ed15719ff --- /dev/null +++ b/docs/api/chain/tx.md @@ -0,0 +1,84 @@ + + +# autonomy.chain.tx + +Tx settlement helper. + + + +#### should`_`retry + +```python +def should_retry(error: str) -> bool +``` + +Check an error message to check if we should raise an error or retry the tx + + + +#### should`_`reprice + +```python +def should_reprice(error: str) -> bool +``` + +Check an error message to check if we should reprice the transaction + + + +## TxSettler Objects + +```python +class TxSettler() +``` + +Tx settlement helper + + + +#### `__`init`__` + +```python +def __init__(ledger_api: LedgerApi, + crypto: Crypto, + chain_type: ChainType, + timeout: Optional[float] = None, + retries: Optional[int] = None, + sleep: Optional[float] = None) -> None +``` + +Initialize object. + + + +#### build + +```python +def build(method: Callable[[], Dict], contract: str, kwargs: Dict) -> Dict +``` + +Build transaction. + + + +#### transact + +```python +def transact(method: Callable[[], Dict], + contract: str, + kwargs: Dict, + dry_run: bool = False) -> Dict +``` + +Make a transaction and return a receipt + + + +#### process + +```python +def process(event: str, receipt: Dict, contract: PublicId) -> Dict +``` + +Process tx receipt. + diff --git a/docs/api/chain/utils.md b/docs/api/chain/utils.md index 1bd8a74043..56f308746a 100644 --- a/docs/api/chain/utils.md +++ b/docs/api/chain/utils.md @@ -4,6 +4,16 @@ Utility functions. + + +#### get`_`ipfs`_`hash`_`from`_`uri + +```python +def get_ipfs_hash_from_uri(uri: str) -> str +``` + +Split IPFS hash from the ipfs uri + #### resolve`_`component`_`id @@ -28,3 +38,41 @@ def parse_public_id_from_metadata(id_string: str) -> PublicId Parse public ID from on-chain metadata. + + +#### verify`_`component`_`dependencies + +```python +def verify_component_dependencies(ledger_api: LedgerApi, + contract_address: str, + dependencies: List[int], + package_configuration: PackageConfiguration, + skip_hash_check: bool = False) -> None +``` + +Verify package dependencies using on-chain metadata. + + + +#### verify`_`service`_`dependencies + +```python +def verify_service_dependencies(ledger_api: LedgerApi, + contract_address: str, + agent_id: int, + service_configuration: Service, + skip_hash_check: bool = False) -> None +``` + +Verify package dependencies using on-chain metadata. + + + +#### is`_`service`_`manager`_`token`_`compatible`_`chain + +```python +def is_service_manager_token_compatible_chain(ledger_api: LedgerApi) -> bool +``` + +Verify package dependencies using on-chain metadata. + diff --git a/docs/api/cli/build_images.md b/docs/api/cli/build_images.md index ee629ba29c..c3cb1bcb4d 100644 --- a/docs/api/cli/build_images.md +++ b/docs/api/cli/build_images.md @@ -20,6 +20,14 @@ Build images. type=click.Path(dir_okay=True), help="Path to service dir.", ) +@click.option( + "-e", + "--extra-dependency", + "extra_dependencies", + type=PyPiDependency(), + help="Provide extra dependency.", + multiple=True, +) @click.option("--version", type=str, help="Specify tag version for the image.") @click.option("--dev", is_flag=True, @@ -29,9 +37,21 @@ Build images. is_flag=True, help="Pull latest dependencies.", default=False) +@click.option( + "-f", + "--dockerfile", + type=click.Path( + file_okay=True, + dir_okay=False, + exists=False, + ), + help="Specify custom dockerfile for building the agent", +) @image_author_option def build_image(agent: Optional[PublicId], service_dir: Optional[Path], + dockerfile: Optional[Path], + extra_dependencies: Tuple[Dependency, ...], pull: bool = False, dev: bool = False, version: Optional[str] = None, diff --git a/docs/api/cli/deploy.md b/docs/api/cli/deploy.md index b92e900dd3..ae51cb7074 100644 --- a/docs/api/cli/deploy.md +++ b/docs/api/cli/deploy.md @@ -10,8 +10,18 @@ Deploy CLI module. ```python @click.group(name="deploy") +@click.option( + "--env-file", + type=PathArgument( + exists=True, + dir_okay=False, + file_okay=True, + ), + help="File containing environment variable mappings", +) @click.pass_context -def deploy_group(click_context: click.Context) -> None +def deploy_group(click_context: click.Context, + env_file: Optional[Path]) -> None ``` Deploy an agent service. @@ -139,6 +149,7 @@ Build deployment setup for n agents. @click.option( "--build-dir", type=click.Path(), + help="Path to the deployment build directory.", ) @click.option( "--no-recreate", @@ -152,11 +163,36 @@ Build deployment setup for n agents. default=False, help="Remove containers for services not defined in the Compose file.", ) -def run(build_dir: Path, no_recreate: bool, remove_orphans: bool) -> None +@click.option( + "--detach", + is_flag=True, + default=False, + help="Run service in the background.", +) +def run(build_dir: Path, + no_recreate: bool, + remove_orphans: bool, + detach: bool = False) -> None ``` Run deployment. + + +#### stop + +```python +@deploy_group.command(name="stop") +@click.option( + "--build-dir", + type=click.Path(), + help="Path to the deployment build directory.", +) +def stop(build_dir: Path) -> None +``` + +Stop a running deployment. + #### run`_`deployment`_`from`_`token @@ -196,6 +232,12 @@ Run deployment. is_flag=True, help="If set to true, the deployment won't run automatically", ) +@click.option( + "--detach", + is_flag=True, + default=False, + help="Run service in the background.", +) @chain_selection_flag( help_string_format="Use {} chain to resolve the token id.") @click.pass_context @@ -208,6 +250,7 @@ def run_deployment_from_token(click_context: click.Context, n: Optional[int], deployment_type: str, no_deploy: bool, + detach: bool, aev: bool = False, password: Optional[str] = None) -> None ``` diff --git a/docs/api/cli/helpers/analyse.md b/docs/api/cli/helpers/analyse.md index 7927270006..021d7e6e78 100644 --- a/docs/api/cli/helpers/analyse.md +++ b/docs/api/cli/helpers/analyse.md @@ -157,7 +157,9 @@ Print table. ```python def check_service_readiness(token_id: Optional[int], public_id: Optional[PublicId], - chain_type: ChainType, packages_dir: Path) -> None + chain_type: ChainType, + packages_dir: Path, + skip_warnings: bool = False) -> None ``` Check deployment readiness of a service. diff --git a/docs/api/cli/helpers/chain.md b/docs/api/cli/helpers/chain.md index fa4c93c64e..de84fc4539 100644 --- a/docs/api/cli/helpers/chain.md +++ b/docs/api/cli/helpers/chain.md @@ -4,12 +4,63 @@ On-chain interaction helpers. - + + +## OnChainHelper Objects + +```python +class OnChainHelper() +``` + +On-chain interaction helper. + + + +#### `__`init`__` + +```python +def __init__(chain_type: ChainType, + key: Optional[Path] = None, + password: Optional[str] = None, + hwi: bool = False, + timeout: Optional[float] = None, + retries: Optional[int] = None, + sleep: Optional[float] = None, + dry_run: bool = False) -> None +``` + +Initialize object. + + + +#### load`_`hwi`_`plugin + +```python +@staticmethod +def load_hwi_plugin() -> Type[LedgerApi] +``` + +Load HWI Plugin. + + + +#### load`_`crypto + +```python +@staticmethod +def load_crypto(file: Path, password: Optional[str] = None) -> Crypto +``` + +Load crypto object. + + #### get`_`ledger`_`and`_`crypto`_`objects ```python +@classmethod def get_ledger_and_crypto_objects( + cls, chain_type: ChainType, key: Optional[Path] = None, password: Optional[str] = None, @@ -18,107 +69,286 @@ def get_ledger_and_crypto_objects( Create ledger_api and crypto objects - + + +#### check`_`required`_`enviroment`_`variables + +```python +def check_required_enviroment_variables( + configs: Tuple[ContractConfig, ...]) -> None +``` + +Check for required enviroment variables when working with the custom chain. + + + +## MintHelper Objects + +```python +class MintHelper(OnChainHelper) +``` + +Mint helper. + + + +#### `__`init`__` + +```python +def __init__(chain_type: ChainType, + key: Optional[Path] = None, + password: Optional[str] = None, + hwi: bool = False, + update_token: Optional[int] = None, + timeout: Optional[float] = None, + retries: Optional[int] = None, + sleep: Optional[float] = None, + dry_run: bool = False) -> None +``` + +Initialize object. + + + +#### load`_`package`_`configuration + +```python +def load_package_configuration(package_path: Path, + package_type: PackageType) -> "MintHelper" +``` + +Load package configuration. + + + +#### load`_`metadata + +```python +def load_metadata() -> "MintHelper" +``` + +Load metadata when updating a mint. + + + +#### verify`_`nft + +```python +def verify_nft(nft: Optional[NFTHashOrPath] = None) -> "MintHelper" +``` + +Verify NFT image. + + + +#### verify`_`component`_`dependencies + +```python +def verify_component_dependencies( + dependencies: Tuple[str], + skip_dependencies_check: bool = False, + skip_hash_check: bool = False) -> "MintHelper" +``` + +Verify component dependencies. + + + +#### verify`_`service`_`dependencies + +```python +def verify_service_dependencies(agent_id: int, + skip_dependencies_check: bool = False, + skip_hash_check: bool = False) -> "MintHelper" +``` + +Verify component dependencies. + + -#### get`_`on`_`chain`_`dependencies +#### publish`_`metadata ```python -def get_on_chain_dependencies( - dependencies: Set[PackageId], - skip_hash_check: bool = False, - use_latest_dependencies: bool = False) -> List[int] +def publish_metadata() -> "MintHelper" ``` -Get package dependencies +Publish metadata. - + #### mint`_`component ```python -def mint_component(package_path: Path, - package_type: PackageType, - key: Optional[Path], - chain_type: ChainType, - nft: Optional[NFTHashOrPath] = None, - owner: Optional[str] = None, - password: Optional[str] = None, - skip_hash_check: bool = False, - use_latest_dependencies: bool = False, - timeout: Optional[float] = None, - hwi: bool = False) -> None +def mint_component(owner: Optional[str] = None, + component_type: UnitType = UnitType.COMPONENT) -> None ``` Mint component. - + + +#### mint`_`agent + +```python +def mint_agent(owner: Optional[str] = None) -> None +``` + +Mint agent. + + #### mint`_`service ```python -def mint_service(package_path: Path, - key: Optional[Path], - chain_type: ChainType, - agent_id: int, - number_of_slots: int, +def mint_service(number_of_slots: int, cost_of_bond: int, threshold: int, - nft: Optional[NFTHashOrPath] = None, - owner: Optional[str] = None, - password: Optional[str] = None, - skip_hash_check: bool = False, - use_latest_dependencies: bool = False, - timeout: Optional[float] = None, - hwi: bool = False) -> None + token: Optional[str] = None, + owner: Optional[str] = None) -> None ``` Mint service - + + +#### update`_`component + +```python +def update_component(component_type: UnitType = UnitType.COMPONENT) -> None +``` + +Update component. + + + +#### update`_`agent + +```python +def update_agent() -> None +``` + +Update agent. + + + +#### update`_`service + +```python +def update_service(number_of_slots: int, + cost_of_bond: int, + threshold: int, + token: Optional[str] = None) -> None +``` + +Update service + + + +## ServiceHelper Objects + +```python +class ServiceHelper(OnChainHelper) +``` + +Service helper. + + + +#### `__`init`__` + +```python +def __init__(service_id: int, + chain_type: ChainType, + key: Optional[Path] = None, + password: Optional[str] = None, + hwi: bool = False, + timeout: Optional[float] = None, + retries: Optional[int] = None, + sleep: Optional[float] = None, + dry_run: bool = False) -> None +``` + +Initialize object. + + + +#### check`_`is`_`service`_`token`_`secured + +```python +def check_is_service_token_secured( + token: Optional[str] = None) -> "ServiceHelper" +``` + +Check if service + + + +#### approve`_`erc20`_`usage + +```python +def approve_erc20_usage(amount: int, spender: str) -> "ServiceHelper" +``` + +Approve ERC20 usage. + + #### activate`_`service ```python -def activate_service(service_id: int, - key: Path, - chain_type: ChainType, - password: Optional[str] = None, - timeout: Optional[float] = None, - hwi: bool = False) -> None +def activate_service() -> None ``` Activate on-chain service - + #### register`_`instance ```python -def register_instance(service_id: int, - instances: List[str], - agent_ids: List[int], - key: Path, - chain_type: ChainType, - password: Optional[str] = None, - timeout: Optional[float] = None, - hwi: bool = False) -> None +def register_instance(instances: List[str], agent_ids: List[int]) -> None ``` Register agents instances on an activated service - + #### deploy`_`service ```python -def deploy_service(service_id: int, - key: Path, - chain_type: ChainType, - deployment_payload: Optional[str] = None, - password: Optional[str] = None, - timeout: Optional[float] = None, - hwi: bool = False) -> None +def deploy_service(reuse_multisig: bool = False, + fallback_handler: Optional[str] = None) -> None ``` Deploy a service with registration activated + + +#### terminate`_`service + +```python +def terminate_service() -> None +``` + +Terminate a service + + + +#### unbond`_`service + +```python +def unbond_service() -> None +``` + +Unbond a service + + + +#### print`_`service`_`info + +```python +def print_service_info(service_id: int, chain_type: ChainType) -> None +``` + +Print service information + diff --git a/docs/api/cli/helpers/deployment.md b/docs/api/cli/helpers/deployment.md index b0bb1110fe..17383da163 100644 --- a/docs/api/cli/helpers/deployment.md +++ b/docs/api/cli/helpers/deployment.md @@ -11,11 +11,22 @@ Deployment helpers. ```python def run_deployment(build_dir: Path, no_recreate: bool = False, - remove_orphans: bool = False) -> None + remove_orphans: bool = False, + detach: bool = False) -> None ``` Run deployment. + + +#### stop`_`deployment + +```python +def stop_deployment(build_dir: Path) -> None +``` + +Stop running deployment. + #### build`_`deployment @@ -26,7 +37,6 @@ def build_deployment(keys_file: Path, deployment_type: str, dev_mode: bool, number_of_agents: Optional[int] = None, - password: Optional[str] = None, packages_dir: Optional[Path] = None, open_aea_dir: Optional[Path] = None, open_autonomy_dir: Optional[Path] = None, @@ -56,8 +66,8 @@ def build_and_deploy_from_token(token_id: int, n: Optional[int], deployment_type: str, aev: bool = False, - password: Optional[str] = None, - no_deploy: bool = False) -> None + no_deploy: bool = False, + detach: bool = False) -> None ``` Build and run deployment from tokenID. diff --git a/docs/api/cli/helpers/env.md b/docs/api/cli/helpers/env.md new file mode 100644 index 0000000000..4be748cb0a --- /dev/null +++ b/docs/api/cli/helpers/env.md @@ -0,0 +1,26 @@ + + +# autonomy.cli.helpers.env + +Environment variable helpers. + + + +#### load`_`json + +```python +def load_json(file: Path, serialize: bool = False) -> None +``` + +Load json. + + + +#### load`_`env`_`file + +```python +def load_env_file(file: Path, serialize_json: bool = False) -> None +``` + +Load env file. + diff --git a/docs/api/cli/helpers/image.md b/docs/api/cli/helpers/image.md new file mode 100644 index 0000000000..d1053064cc --- /dev/null +++ b/docs/api/cli/helpers/image.md @@ -0,0 +1,23 @@ + + +# autonomy.cli.helpers.image + +Image helpers. + + + +#### build`_`image + +```python +def build_image(agent: Optional[PublicId], + service_dir: Optional[Path], + pull: bool = False, + dev: bool = False, + version: Optional[str] = None, + image_author: Optional[str] = None, + extra_dependencies: Optional[Tuple[Dependency, ...]] = None, + dockerfile: Optional[Path] = None) -> None +``` + +Build agent/service image. + diff --git a/docs/api/cli/helpers/registry.md b/docs/api/cli/helpers/registry.md index ca759b3f75..a13b46c7b3 100644 --- a/docs/api/cli/helpers/registry.md +++ b/docs/api/cli/helpers/registry.md @@ -9,7 +9,9 @@ Component registry helpers. #### fetch`_`service ```python -def fetch_service(ctx: Context, public_id: PublicId) -> Path +def fetch_service(ctx: Context, + public_id: PublicId, + alias: Optional[str] = None) -> Path ``` Fetch service. @@ -19,7 +21,9 @@ Fetch service. #### fetch`_`service`_`mixed ```python -def fetch_service_mixed(ctx: Context, public_id: PublicId) -> Path +def fetch_service_mixed(ctx: Context, + public_id: PublicId, + alias: Optional[str] = None) -> Path ``` Fetch service in mixed mode. @@ -29,7 +33,8 @@ Fetch service in mixed mode. #### fetch`_`service`_`remote ```python -def fetch_service_remote(public_id: PublicId) -> Path +def fetch_service_remote(public_id: PublicId, + alias: Optional[str] = None) -> Path ``` Fetch service in remote mode. @@ -39,7 +44,8 @@ Fetch service in remote mode. #### fetch`_`service`_`ipfs ```python -def fetch_service_ipfs(public_id: PublicId) -> Path +def fetch_service_ipfs(public_id: PublicId, + alias: Optional[str] = None) -> Path ``` Fetch service from IPFS node. @@ -49,7 +55,9 @@ Fetch service from IPFS node. #### fetch`_`service`_`local ```python -def fetch_service_local(ctx: Context, public_id: PublicId) -> Path +def fetch_service_local(ctx: Context, + public_id: PublicId, + alias: Optional[str] = None) -> Path ``` Fetch service from local directory. diff --git a/docs/api/cli/mint.md b/docs/api/cli/mint.md index f304a5deea..e286f8c7ed 100644 --- a/docs/api/cli/mint.md +++ b/docs/api/cli/mint.md @@ -13,22 +13,22 @@ Mint command group definitions. @pass_ctx @chain_selection_flag() @timeout_flag +@retries_flag +@sleep_flag +@dry_run_flag @click.option( - "-s", "--skip-hash-check", is_flag=True, help="Skip hash check when verifying dependencies on chain", ) @click.option( - "-l", - "--latest-dependencies", - "use_latest_dependencies", + "--skip-dependencies-check", is_flag=True, - help= - "Use latest on-chain dependencies if there are multiple dependencies with same package ID", + help="Skip dependencies check.", ) def mint(ctx: Context, chain_type: str, skip_hash_check: bool, - use_latest_dependencies: bool, timeout: float) -> None + skip_dependencies_check: bool, timeout: float, retries: int, + sleep: float, dry_run: bool) -> None ``` Mint component on-chain. @@ -43,15 +43,19 @@ Mint component on-chain. @key_path_decorator @hwi_flag @password_decorator +@dependencies_decorator @nft_decorator @owner_flag +@update_flag @pass_ctx def protocol(ctx: Context, package_path: Path, key: Path, password: Optional[str], + dependencies: Tuple[str], nft: Optional[Union[Path, IPFSHash]], owner: Optional[str], + update: Optional[int], hwi: bool = False) -> None ``` @@ -67,15 +71,19 @@ Mint a protocol component. @key_path_decorator @hwi_flag @password_decorator +@dependencies_decorator @nft_decorator @owner_flag +@update_flag @pass_ctx def contract(ctx: Context, package_path: Path, key: Path, password: Optional[str], + dependencies: Tuple[str], nft: Optional[Union[Path, IPFSHash]], owner: Optional[str], + update: Optional[int], hwi: bool = False) -> None ``` @@ -91,15 +99,19 @@ Mint a contract component. @key_path_decorator @hwi_flag @password_decorator +@dependencies_decorator @nft_decorator @owner_flag +@update_flag @pass_ctx def connection(ctx: Context, package_path: Path, key: Path, password: Optional[str], + dependencies: Tuple[str], nft: Optional[Union[Path, IPFSHash]], owner: Optional[str], + update: Optional[int], hwi: bool = False) -> None ``` @@ -115,15 +127,19 @@ Mint a connection component. @key_path_decorator @hwi_flag @password_decorator +@dependencies_decorator @nft_decorator @owner_flag +@update_flag @pass_ctx def skill(ctx: Context, package_path: Path, key: Path, password: Optional[str], + dependencies: Tuple[str], nft: Optional[Union[Path, IPFSHash]], owner: Optional[str], + update: Optional[int], hwi: bool = False) -> None ``` @@ -139,15 +155,19 @@ Mint a skill component. @key_path_decorator @hwi_flag @password_decorator +@dependencies_decorator @nft_decorator @owner_flag +@update_flag @pass_ctx def agent(ctx: Context, package_path: Path, key: Path, password: Optional[str], + dependencies: Tuple[str], nft: Optional[Union[Path, IPFSHash]], owner: Optional[str], + update: Optional[int], hwi: bool = False) -> None ``` @@ -165,6 +185,8 @@ Mint an agent. @password_decorator @nft_decorator @owner_flag +@update_flag +@token_flag @pass_ctx @click.option( "-a", @@ -203,6 +225,8 @@ def service(ctx: Context, password: Optional[str], nft: Optional[Union[Path, IPFSHash]], owner: Optional[str], + update: Optional[int], + token: Optional[str], hwi: bool = False) -> None ``` diff --git a/docs/api/cli/packages.md b/docs/api/cli/packages.md index 3f54341b52..cede5b7818 100644 --- a/docs/api/cli/packages.md +++ b/docs/api/cli/packages.md @@ -15,8 +15,13 @@ Override for packages command. is_flag=True, help="Check that fingerprints in packages.json match the local packages", ) +@click.option( + "--skip-missing", + is_flag=True, + help="Skip packages missing from the `packages.json` file.", +) @pass_ctx -def lock_packages(ctx: Context, check: bool) -> None +def lock_packages(ctx: Context, check: bool, skip_missing: bool) -> None ``` Lock local packages. diff --git a/docs/api/cli/scaffold_fsm.md b/docs/api/cli/scaffold_fsm.md index 78ecd10cc6..96f4041250 100644 --- a/docs/api/cli/scaffold_fsm.md +++ b/docs/api/cli/scaffold_fsm.md @@ -12,7 +12,7 @@ This module patches the 'aea scaffold' command so to add a new subcommand for sc #### fsm ```python -@scaffold.command() # noqa +@scaffold.command() @registry_flag() @click.argument("skill_name", type=str, required=True) @click.option("--spec", diff --git a/docs/api/cli/service.md b/docs/api/cli/service.md index 588a5086a8..87940a0ed0 100644 --- a/docs/api/cli/service.md +++ b/docs/api/cli/service.md @@ -11,86 +11,14 @@ Implementation of the `autonomy service` command ```python @click.group("service") @pass_ctx -@chain_selection_flag() @timeout_flag -def service(ctx: Context, chain_type: str, timeout: float) -> None +@retries_flag +@sleep_flag +@dry_run_flag +@chain_selection_flag() +def service(ctx: Context, chain_type: str, timeout: float, retries: int, + sleep: float, dry_run: bool) -> None ``` Manage on-chain services. - - -#### activate - -```python -@service.command() -@pass_ctx -@click.argument("service_id", type=int) -@key_path_decorator -@hwi_flag -@password_decorator -def activate(ctx: Context, service_id: int, key: Path, hwi: bool, - password: Optional[str]) -> None -``` - -Activate service. - - - -#### register - -```python -@service.command() -@pass_ctx -@click.argument("service_id", type=int) -@click.option( - "-i", - "--instance", - "instances", - type=str, - required=True, - multiple=True, - help="Agent instance address", -) -@click.option( - "-a", - "--agent-id", - "agent_ids", - type=int, - required=True, - multiple=True, - help="Agent ID", -) -@key_path_decorator -@hwi_flag -@password_decorator -def register(ctx: Context, service_id: int, instances: List[str], - agent_ids: List[int], key: Path, hwi: bool, - password: Optional[str]) -> None -``` - -Register instances. - - - -#### deploy - -```python -@service.command() -@pass_ctx -@click.argument("service_id", type=int) -@click.option( - "-d", - "--deployment-payload", - type=int, - help="Deployment payload value", -) -@key_path_decorator -@hwi_flag -@password_decorator -def deploy(ctx: Context, service_id: int, key: Path, hwi: bool, - password: Optional[str], deployment_payload: Optional[str]) -> None -``` - -Activate service. - diff --git a/docs/api/configurations/base.md b/docs/api/configurations/base.md index 0b442fef44..417d73e54c 100644 --- a/docs/api/configurations/base.md +++ b/docs/api/configurations/base.md @@ -4,6 +4,16 @@ Base configurations. + + +#### load`_`dependencies + +```python +def load_dependencies(dependencies: Dict) -> Dependencies +``` + +Load dependencies. + ## Service Objects @@ -31,7 +41,8 @@ def __init__(name: SimpleIdOrStr, number_of_agents: int = 4, build_entrypoint: Optional[str] = None, overrides: Optional[List] = None, - deployment: Optional[Dict] = None) -> None + deployment: Optional[Dict] = None, + dependencies: Optional[Dependencies] = None) -> None ``` Initialise object. diff --git a/docs/api/connections/abci/connection.md b/docs/api/connections/abci/connection.md index e69de29bb2..428c78827f 100644 --- a/docs/api/connections/abci/connection.md +++ b/docs/api/connections/abci/connection.md @@ -0,0 +1,937 @@ + + +# packages.valory.connections.abci.connection + +Connection to interact with an ABCI server. + + + +#### DEFAULT`_`LISTEN`_`ADDRESS + +nosec + + + +#### MAX`_`READ`_`IN`_`BYTES + +Max we'll consume on a read stream (1 MiB) + + + +#### MAX`_`VARINT`_`BYTES + +Max size of varint we support + + + +## DecodeVarintError Objects + +```python +class DecodeVarintError(Exception) +``` + +This exception is raised when an error occurs while decoding a varint. + + + +## EncodeVarintError Objects + +```python +class EncodeVarintError(Exception) +``` + +This exception is raised when an error occurs while encoding a varint. + + + +## TooLargeVarint Objects + +```python +class TooLargeVarint(Exception) +``` + +This exception is raised when a message with varint exceeding the max size is received. + + + +#### `__`init`__` + +```python +def __init__(received_size: int, max_size: int = MAX_READ_IN_BYTES) +``` + +Initialize the exception object. + +**Arguments**: + +- `received_size`: the received size. +- `max_size`: the maximum amount the connection supports. + + + +## ShortBufferLengthError Objects + +```python +class ShortBufferLengthError(Exception) +``` + +This exception is raised when the buffer length is shorter than expected. + + + +#### `__`init`__` + +```python +def __init__(expected_length: int, data: bytes) +``` + +Initialize the exception object. + +**Arguments**: + +- `expected_length`: the expected length to be read +- `data`: the data actually read + + + +## `_`TendermintABCISerializer Objects + +```python +class _TendermintABCISerializer() +``` + +(stateless) utility class to encode/decode messages for the communication with Tendermint. + + + +#### encode`_`varint + +```python +@classmethod +def encode_varint(cls, number: int) -> bytes +``` + +Encode a number in varint coding. + + + +#### decode`_`varint + +```python +@classmethod +async def decode_varint(cls, + buffer: asyncio.StreamReader, + max_length: int = MAX_VARINT_BYTES) -> int +``` + +Decode a number from its varint coding. + +**Arguments**: + +- `buffer`: the buffer to read from. +- `max_length`: the max number of bytes that can be read. + +**Raises**: + +- `None`: DecodeVarintError if the varint could not be decoded. +- `None`: EOFError if EOF byte is read and the process of decoding a varint has not started. + +**Returns**: + +the decoded int. + + + +#### write`_`message + +```python +@classmethod +def write_message(cls, message: Response) -> bytes +``` + +Write a message in a buffer. + + + +## VarintMessageReader Objects + +```python +class VarintMessageReader() +``` + +Varint message reader. + + + +#### `__`init`__` + +```python +def __init__(reader: asyncio.StreamReader) -> None +``` + +Initialize the reader. + + + +#### read`_`next`_`message + +```python +async def read_next_message() -> bytes +``` + +Read next message. + + + +#### read`_`until + +```python +async def read_until(n: int) -> bytes +``` + +Wait until n bytes are read from the stream. + + + +## ABCIApplicationServicer Objects + +```python +class ABCIApplicationServicer(types_pb2_grpc.ABCIApplicationServicer) +``` + +Implements the gRPC servicer (handler) + + + +#### `__`init`__` + +```python +def __init__(request_queue: asyncio.Queue, dialogues: AbciDialogues, + target_skill: str) +``` + +Initializes the abci handler. + +**Arguments**: + +- `request_queue`: queue holding translated abci messages. +- `dialogues`: dialogues +- `target_skill`: target skill of messages + + + +#### send + +```python +async def send(envelope: Envelope) -> Response +``` + +Returns response to the waiting request + +:param: envelope: Envelope to be returned + + + + +#### Echo + +```python +async def Echo(request: RequestEcho, + context: grpc.ServicerContext) -> ResponseEcho +``` + +Handles "Echo" gRPC requests + +:param: request: The request from the Tendermint node +:param: context: The request context +:return: the Echo response + + + + +#### Flush + +```python +async def Flush(request: RequestFlush, + context: grpc.ServicerContext) -> ResponseFlush +``` + +Handles "Flush" gRPC requests + +:param: request: The request from the Tendermint node +:param: context: The request context +:return: the Echo response + + + + +#### Info + +```python +async def Info(request: RequestInfo, + context: grpc.ServicerContext) -> ResponseInfo +``` + +Handles "Info" gRPC requests + +:param: request: The request from the Tendermint node +:param: context: The request context +:return: the Echo response + + + + +#### SetOption + +```python +async def SetOption(request: RequestSetOption, + context: grpc.ServicerContext) -> ResponseSetOption +``` + +Handles "SetOption" gRPC requests + +:param: request: The request from the Tendermint node +:param: context: The request context +:return: the Echo response + + + + +#### DeliverTx + +```python +async def DeliverTx(request: RequestDeliverTx, + context: grpc.ServicerContext) -> ResponseDeliverTx +``` + +Handles "DeliverTx" gRPC requests + +:param: request: The request from the Tendermint node +:param: context: The request context +:return: the Echo response + + + + +#### CheckTx + +```python +async def CheckTx(request: RequestCheckTx, + context: grpc.ServicerContext) -> ResponseCheckTx +``` + +Handles "CheckTx" gRPC requests + +:param: request: The request from the Tendermint node +:param: context: The request context +:return: the Echo response + + + + +#### Query + +```python +async def Query(request: RequestQuery, + context: grpc.ServicerContext) -> ResponseQuery +``` + +Handles "Query" gRPC requests + +:param: request: The request from the Tendermint node +:param: context: The request context +:return: the Echo response + + + + +#### Commit + +```python +async def Commit(request: RequestCommit, + context: grpc.ServicerContext) -> ResponseCommit +``` + +Handles "Commit" gRPC requests + +:param: request: The request from the Tendermint node +:param: context: The request context +:return: the Echo response + + + + +#### InitChain + +```python +async def InitChain(request: RequestInitChain, + context: grpc.ServicerContext) -> ResponseInitChain +``` + +Handles "InitChain" gRPC requests + +:param: request: The request from the Tendermint node +:param: context: The request context +:return: the Echo response + + + + +#### BeginBlock + +```python +async def BeginBlock(request: RequestBeginBlock, + context: grpc.ServicerContext) -> ResponseBeginBlock +``` + +Handles "BeginBlock" gRPC requests + +:param: request: The request from the Tendermint node +:param: context: The request context +:return: the Echo response + + + + +#### EndBlock + +```python +async def EndBlock(request: RequestEndBlock, + context: grpc.ServicerContext) -> ResponseEndBlock +``` + +Handles "EndBlock" gRPC requests + +:param: request: The request from the Tendermint node +:param: context: The request context +:return: the Echo response + + + + +#### ListSnapshots + +```python +async def ListSnapshots( + request: RequestListSnapshots, + context: grpc.ServicerContext) -> ResponseListSnapshots +``` + +Handles "ListSnapshots" gRPC requests + +:param: request: The request from the Tendermint node +:param: context: The request context +:return: the Echo response + + + + +#### OfferSnapshot + +```python +async def OfferSnapshot( + request: RequestOfferSnapshot, + context: grpc.ServicerContext) -> ResponseOfferSnapshot +``` + +Handles "OfferSnapshot" gRPC requests + +:param: request: The request from the Tendermint node +:param: context: The request context +:return: the Echo response + + + + +#### LoadSnapshotChunk + +```python +async def LoadSnapshotChunk( + request: RequestLoadSnapshotChunk, + context: grpc.ServicerContext) -> ResponseLoadSnapshotChunk +``` + +Handles "LoadSnapshotChunk" gRPC requests + +:param: request: The request from the Tendermint node +:param: context: The request context +:return: the Echo response + + + + +#### ApplySnapshotChunk + +```python +async def ApplySnapshotChunk( + request: RequestApplySnapshotChunk, + context: grpc.ServicerContext) -> ResponseApplySnapshotChunk +``` + +Handles "ApplySnapshotChunk" gRPC requests + +:param: request: The request from the Tendermint node +:param: context: The request context +:return: the Echo response + + + + +## GrpcServerChannel Objects + +```python +class GrpcServerChannel() +``` + +gRPC server channel to handle incoming communication from the Tendermint node. + + + +#### `__`init`__` + +```python +def __init__(target_skill_id: PublicId, + address: str, + port: int, + logger: Optional[Logger] = None) +``` + +Initialize the gRPC server. + +**Arguments**: + +- `target_skill_id`: the public id of the target skill. +- `address`: the listen address. +- `port`: the port to listen from. +- `logger`: the logger. + + + +#### is`_`stopped + +```python +@property +def is_stopped() -> bool +``` + +Check that the channel is stopped. + + + +#### connect + +```python +async def connect(loop: AbstractEventLoop) -> None +``` + +Connect. + +**Arguments**: + +- `loop`: asyncio event loop + + + +#### disconnect + +```python +async def disconnect() -> None +``` + +Disconnect the channel + + + +#### get`_`message + +```python +async def get_message() -> Envelope +``` + +Get a message from the queue. + + + +#### send + +```python +async def send(envelope: Envelope) -> None +``` + +Send a message. + + + +## TcpServerChannel Objects + +```python +class TcpServerChannel() +``` + +TCP server channel to handle incoming communication from the Tendermint node. + + + +#### `__`init`__` + +```python +def __init__(target_skill_id: PublicId, + address: str, + port: int, + logger: Optional[Logger] = None) +``` + +Initialize the TCP server. + +**Arguments**: + +- `target_skill_id`: the public id of the target skill. +- `address`: the listen address. +- `port`: the port to listen from. +- `logger`: the logger. + + + +#### is`_`stopped + +```python +@property +def is_stopped() -> bool +``` + +Check that the channel is stopped. + + + +#### connect + +```python +async def connect(loop: AbstractEventLoop) -> None +``` + +Connect. + +Upon TCP Channel connection, start the TCP Server asynchronously. + +**Arguments**: + +- `loop`: asyncio event loop + + + +#### disconnect + +```python +async def disconnect() -> None +``` + +Disconnect the channel + + + +#### receive`_`messages + +```python +async def receive_messages(reader: asyncio.StreamReader, + writer: asyncio.StreamWriter) -> None +``` + +Receive incoming messages. + + + +#### get`_`message + +```python +async def get_message() -> Envelope +``` + +Get a message from the queue. + + + +#### send + +```python +async def send(envelope: Envelope) -> None +``` + +Send a message. + + + +## StoppableThread Objects + +```python +class StoppableThread(Thread) +``` + +Thread class with a stop() method. + + + +#### `__`init`__` + +```python +def __init__(*args: Any, **kwargs: Any) -> None +``` + +Initialise the thread. + + + +#### stop + +```python +def stop() -> None +``` + +Set the stop event. + + + +#### stopped + +```python +def stopped() -> bool +``` + +Check if the thread is stopped. + + + +## TendermintParams Objects + +```python +class TendermintParams() +``` + +Tendermint node parameters. + + + +#### `__`init`__` + +```python +def __init__(proxy_app: str, + rpc_laddr: str = DEFAULT_RPC_LISTEN_ADDRESS, + p2p_laddr: str = DEFAULT_P2P_LISTEN_ADDRESS, + p2p_seeds: Optional[List[str]] = None, + consensus_create_empty_blocks: bool = True, + home: Optional[str] = None, + use_grpc: bool = False) +``` + +Initialize the parameters to the Tendermint node. + +**Arguments**: + +- `proxy_app`: ABCI address. +- `rpc_laddr`: RPC address. +- `p2p_laddr`: P2P address. +- `p2p_seeds`: P2P seeds. +- `consensus_create_empty_blocks`: if true, Tendermint node creates empty blocks. +- `home`: Tendermint's home directory. +- `use_grpc`: Whether to use a gRPC server, or TCP + + + +#### `__`str`__` + +```python +def __str__() -> str +``` + +Get the string representation. + + + +#### build`_`node`_`command + +```python +def build_node_command(debug: bool = False) -> List[str] +``` + +Build the 'node' command. + + + +#### get`_`node`_`command`_`kwargs + +```python +@staticmethod +def get_node_command_kwargs() -> Dict +``` + +Get the node command kwargs + + + +## TendermintNode Objects + +```python +class TendermintNode() +``` + +A class to manage a Tendermint node. + + + +#### `__`init`__` + +```python +def __init__(params: TendermintParams, + logger: Optional[Logger] = None, + write_to_log: bool = False) +``` + +Initialize a Tendermint node. + +**Arguments**: + +- `params`: the parameters. +- `logger`: the logger. +- `write_to_log`: Write to log file. + + + +#### init + +```python +def init() -> None +``` + +Initialize Tendermint node. + + + +#### start + +```python +def start(debug: bool = False) -> None +``` + +Start a Tendermint node process. + + + +#### stop + +```python +def stop() -> None +``` + +Stop a Tendermint node process. + + + +#### log + +```python +def log(line: str) -> None +``` + +Open and write a line to the log file. + + + +#### prune`_`blocks + +```python +def prune_blocks() -> int +``` + +Prune blocks from the Tendermint state + + + +#### reset`_`genesis`_`file + +```python +def reset_genesis_file(genesis_time: str, initial_height: str, + period_count: str) -> None +``` + +Reset genesis file. + + + +## ABCIServerConnection Objects + +```python +class ABCIServerConnection(Connection) +``` + +ABCI server. + + + +#### `__`init`__` + +```python +def __init__(**kwargs: Any) -> None +``` + +Initialize the connection. + +**Arguments**: + +- `kwargs`: keyword arguments passed to component base + + + +#### connect + +```python +async def connect() -> None +``` + +Set up the connection. + +In the implementation, remember to update 'connection_status' accordingly. + + + +#### disconnect + +```python +async def disconnect() -> None +``` + +Tear down the connection. + +In the implementation, remember to update 'connection_status' accordingly. + + + +#### send + +```python +async def send(envelope: Envelope) -> None +``` + +Send an envelope. + +**Arguments**: + +- `envelope`: the envelope to send. + + + +#### receive + +```python +async def receive(*args: Any, **kwargs: Any) -> Optional[Envelope] +``` + +Receive an envelope. Blocking. + +**Arguments**: + +- `args`: arguments to receive +- `kwargs`: keyword arguments to receive + +**Returns**: + +the envelope received, if present. # noqa: DAR202 + diff --git a/docs/api/connections/abci/tests/test_fuzz/mock_node/channels/base.md b/docs/api/connections/abci/tests/test_fuzz/mock_node/channels/base.md index e69de29bb2..3693372c18 100644 --- a/docs/api/connections/abci/tests/test_fuzz/mock_node/channels/base.md +++ b/docs/api/connections/abci/tests/test_fuzz/mock_node/channels/base.md @@ -0,0 +1,261 @@ + + +# packages.valory.connections.abci.tests.test`_`fuzz.mock`_`node.channels.base + +BaseChannel for MockNode + + + +## BaseChannel Objects + +```python +class BaseChannel() +``` + +Defines the interface for other channels to use + + + +#### `__`init`__` + +```python +def __init__(**kwargs: Dict) -> None +``` + +Initializes a channel + + + +#### connect + +```python +def connect() -> None +``` + +Set up the channel. + +By default, it is a no-op. + + + +#### disconnect + +```python +def disconnect() -> None +``` + +Tear down the channel. + +By default, it is a no-op. + + + +#### send`_`info + +```python +def send_info(request: abci_types.RequestInfo) -> abci_types.ResponseInfo +``` + +Sends an info request. + +:param: request: RequestInfo pb object + + + + +#### send`_`echo + +```python +def send_echo(request: abci_types.RequestEcho) -> abci_types.ResponseEcho +``` + +Sends an echo request. + +:param: request: RequestEcho pb object + + + + +#### send`_`flush + +```python +def send_flush(request: abci_types.RequestFlush) -> abci_types.ResponseFlush +``` + +Sends an flush request. + +:param: request: RequestFlush pb object + + + + +#### send`_`set`_`option + +```python +def send_set_option( + request: abci_types.RequestSetOption) -> abci_types.ResponseSetOption +``` + +Sends an setOption request. + +:param: request: RequestSetOption pb object + + + + +#### send`_`deliver`_`tx + +```python +def send_deliver_tx( + request: abci_types.RequestDeliverTx) -> abci_types.ResponseDeliverTx +``` + +Sends an deliverTx request. + +:param: request: RequestDeliverTx pb object + + + + +#### send`_`check`_`tx + +```python +def send_check_tx( + request: abci_types.RequestCheckTx) -> abci_types.ResponseCheckTx +``` + +Sends an checkTx request. + +:param: request: RequestCheckTx pb object + + + + +#### send`_`query + +```python +def send_query(request: abci_types.RequestQuery) -> abci_types.ResponseQuery +``` + +Sends an query request. + +:param: request: RequestQuery pb object + + + + +#### send`_`commit + +```python +def send_commit( + request: abci_types.RequestCommit) -> abci_types.ResponseCommit +``` + +Sends an commit request. + +:param: request: RequestCommit pb object + + + + +#### send`_`init`_`chain + +```python +def send_init_chain( + request: abci_types.RequestInitChain) -> abci_types.ResponseInitChain +``` + +Sends an initChain request. + +:param: request: RequestInitChain pb object + + + + +#### send`_`begin`_`block + +```python +def send_begin_block( + request: abci_types.RequestBeginBlock +) -> abci_types.ResponseBeginBlock +``` + +Sends an beginBlock request. + +:param: request: RequestBeginBlock pb object + + + + +#### send`_`end`_`block + +```python +def send_end_block( + request: abci_types.RequestEndBlock) -> abci_types.ResponseEndBlock +``` + +Sends an endBlock request. + +:param: request: RequestEndBlock pb object + + + + +#### send`_`list`_`snapshots + +```python +def send_list_snapshots( + request: abci_types.RequestListSnapshots +) -> abci_types.ResponseListSnapshots +``` + +Sends an listSnapshots request. + +:param: request: RequestListSnapshots pb object + + + + +#### send`_`offer`_`snapshot + +```python +def send_offer_snapshot( + request: abci_types.RequestOfferSnapshot +) -> abci_types.ResponseOfferSnapshot +``` + +Sends an offerSnapshot request. + +:param: request: RequestOfferSnapshot pb object + + + + +#### send`_`load`_`snapshot`_`chunk + +```python +def send_load_snapshot_chunk( + request: abci_types.RequestLoadSnapshotChunk +) -> abci_types.ResponseLoadSnapshotChunk +``` + +Sends an loadSnapshotChunk request. + +:param: request: RequestLoadSnapshotChunk pb object + + + + +#### send`_`apply`_`snapshot`_`chunk + +```python +def send_apply_snapshot_chunk( + request: abci_types.RequestApplySnapshotChunk +) -> abci_types.ResponseApplySnapshotChunk +``` + +Sends an applySnapshotChunk request. + +:param: request: RequestApplySnapshotChunk pb object + + diff --git a/docs/api/connections/abci/tests/test_fuzz/mock_node/channels/grpc_channel.md b/docs/api/connections/abci/tests/test_fuzz/mock_node/channels/grpc_channel.md index e69de29bb2..a8c5da86d4 100644 --- a/docs/api/connections/abci/tests/test_fuzz/mock_node/channels/grpc_channel.md +++ b/docs/api/connections/abci/tests/test_fuzz/mock_node/channels/grpc_channel.md @@ -0,0 +1,257 @@ + + +# packages.valory.connections.abci.tests.test`_`fuzz.mock`_`node.channels.grpc`_`channel + +GrpcChannel for MockNode + + + +## GrpcChannel Objects + +```python +class GrpcChannel(BaseChannel) +``` + +Implements BaseChannel to use gRPC + + + +#### `__`init`__` + +```python +def __init__(**kwargs: Dict) -> None +``` + +Initializes a GrpcChannel + +:param: kwargs: + - host: the host of the ABCI app (localhost by default) + - port: the port of the ABCI app (26658 by default) + + + + +#### send`_`info + +```python +def send_info(request: abci_types.RequestInfo) -> abci_types.ResponseInfo +``` + +Sends an info request. + +:param: request: RequestInfo pb object +:return: ResponseInfo pb object + + + + +#### send`_`echo + +```python +def send_echo(request: abci_types.RequestEcho) -> abci_types.ResponseEcho +``` + +Sends an echo request. + +:param: request: RequestEcho pb object +:return: ResponseEcho pb object + + + + +#### send`_`flush + +```python +def send_flush(request: abci_types.RequestFlush) -> abci_types.ResponseFlush +``` + +Sends an flush request. + +:param: request: RequestFlush pb object +:return: ResponseFlush pb object + + + + +#### send`_`set`_`option + +```python +def send_set_option( + request: abci_types.RequestSetOption) -> abci_types.ResponseSetOption +``` + +Sends an setOption request. + +:param: request: RequestSetOption pb object +:return: ResponseSetOption pb object + + + + +#### send`_`deliver`_`tx + +```python +def send_deliver_tx( + request: abci_types.RequestDeliverTx) -> abci_types.ResponseDeliverTx +``` + +Sends an deliverTx request. + +:param: request: RequestDeliverTx pb object +:return: ResponseDeliverTx pb object + + + + +#### send`_`check`_`tx + +```python +def send_check_tx( + request: abci_types.RequestCheckTx) -> abci_types.ResponseCheckTx +``` + +Sends an checkTx request. + +:param: request: RequestCheckTx pb object +:return: ResponseCheckTx pb object + + + + +#### send`_`query + +```python +def send_query(request: abci_types.RequestQuery) -> abci_types.ResponseQuery +``` + +Sends an query request. + +:param: request: RequestQuery pb object +:return: ResponseQuery pb object + + + + +#### send`_`commit + +```python +def send_commit( + request: abci_types.RequestCommit) -> abci_types.ResponseCommit +``` + +Sends an commit request. + +:param: request: RequestCommit pb object +:return: ResponseCommit pb object + + + + +#### send`_`init`_`chain + +```python +def send_init_chain( + request: abci_types.RequestInitChain) -> abci_types.ResponseInitChain +``` + +Sends an initChain request. + +:param: request: RequestInitChain pb object +:return: ResponseInitChain pb object + + + + +#### send`_`begin`_`block + +```python +def send_begin_block( + request: abci_types.RequestBeginBlock +) -> abci_types.ResponseBeginBlock +``` + +Sends an beginBlock request. + +:param: request: RequestBeginBlock pb object +:return: ResponseBeginBlock pb object + + + + +#### send`_`end`_`block + +```python +def send_end_block( + request: abci_types.RequestEndBlock) -> abci_types.ResponseEndBlock +``` + +Sends an endBlock request. + +:param: request: RequestEndBlock pb object +:return: ResponseEndBlock pb object + + + + +#### send`_`list`_`snapshots + +```python +def send_list_snapshots( + request: abci_types.RequestListSnapshots +) -> abci_types.ResponseListSnapshots +``` + +Sends an listSnapshots request. + +:param: request: RequestListSnapshots pb object +:return: ResponseListSnapshots pb object + + + + +#### send`_`offer`_`snapshot + +```python +def send_offer_snapshot( + request: abci_types.RequestOfferSnapshot +) -> abci_types.ResponseOfferSnapshot +``` + +Sends an offerSnapshot request. + +:param: request: RequestOfferSnapshot pb object +:return: ResponseOfferSnapshot pb object + + + + +#### send`_`load`_`snapshot`_`chunk + +```python +def send_load_snapshot_chunk( + request: abci_types.RequestLoadSnapshotChunk +) -> abci_types.ResponseLoadSnapshotChunk +``` + +Sends an loadSnapshotChunk request. + +:param: request: RequestLoadSnapshotChunk pb object +:return: ResponseLoadSnapshotChunk pb object + + + + +#### send`_`apply`_`snapshot`_`chunk + +```python +def send_apply_snapshot_chunk( + request: abci_types.RequestApplySnapshotChunk +) -> abci_types.ResponseApplySnapshotChunk +``` + +Sends an applySnapshotChunk request. + +:param: request: RequestApplySnapshotChunk pb object +:return: ResponseApplySnapshotChunk pb object + + diff --git a/docs/api/connections/abci/tests/test_fuzz/mock_node/channels/tcp_channel.md b/docs/api/connections/abci/tests/test_fuzz/mock_node/channels/tcp_channel.md index e69de29bb2..8d9f14f035 100644 --- a/docs/api/connections/abci/tests/test_fuzz/mock_node/channels/tcp_channel.md +++ b/docs/api/connections/abci/tests/test_fuzz/mock_node/channels/tcp_channel.md @@ -0,0 +1,294 @@ + + +# packages.valory.connections.abci.tests.test`_`fuzz.mock`_`node.channels.tcp`_`channel + +TcpChannel for MockNode + + + +## TcpChannel Objects + +```python +class TcpChannel(BaseChannel) +``` + +Implements BaseChannel to use TCP sockets + + + +#### MAX`_`READ`_`IN`_`BYTES + +Max we'll consume on a read stream + + + +#### `__`init`__` + +```python +def __init__(**kwargs: Dict) -> None +``` + +Initializes a TcpChannel + +:param: kwargs: + - host: the host of the ABCI app (localhost by default) + - port: the port of the ABCI app (26658 by default) + + + + +#### is`_`connected + +```python +@property +def is_connected() -> bool +``` + +Check whether the channel is connected. + + + +#### connect + +```python +def connect() -> None +``` + +Set up the channel. + + + +#### disconnect + +```python +def disconnect() -> None +``` + +Tear down the channel. + + + +#### send`_`info + +```python +def send_info(request: abci_types.RequestInfo) -> abci_types.ResponseInfo +``` + +Sends an info request. + +:param: request: RequestInfo pb object +:return: ResponseInfo pb object + + + + +#### send`_`echo + +```python +def send_echo(request: abci_types.RequestEcho) -> abci_types.ResponseEcho +``` + +Sends an echo request. + +:param: request: RequestEcho pb object +:return: ResponseEcho pb object + + + + +#### send`_`flush + +```python +def send_flush(request: abci_types.RequestFlush) -> abci_types.ResponseFlush +``` + +Sends an flush request. + +:param: request: RequestFlush pb object +:return: ResponseFlush pb object + + + + +#### send`_`set`_`option + +```python +def send_set_option( + request: abci_types.RequestSetOption) -> abci_types.ResponseSetOption +``` + +Sends an setOption request. + +:param: request: RequestSetOption pb object +:return: ResponseSetOption pb object + + + + +#### send`_`deliver`_`tx + +```python +def send_deliver_tx( + request: abci_types.RequestDeliverTx) -> abci_types.ResponseDeliverTx +``` + +Sends an deliverTx request. + +:param: request: RequestDeliverTx pb object +:return: ResponseDeliverTx pb object + + + + +#### send`_`check`_`tx + +```python +def send_check_tx( + request: abci_types.RequestCheckTx) -> abci_types.ResponseCheckTx +``` + +Sends an checkTx request. + +:param: request: RequestCheckTx pb object +:return: ResponseCheckTx pb object + + + + +#### send`_`query + +```python +def send_query(request: abci_types.RequestQuery) -> abci_types.ResponseQuery +``` + +Sends an query request. + +:param: request: RequestQuery pb object +:return: ResponseQuery pb object + + + + +#### send`_`commit + +```python +def send_commit( + request: abci_types.RequestCommit) -> abci_types.ResponseCommit +``` + +Sends an commit request. + +:param: request: RequestCommit pb object +:return: ResponseCommit pb object + + + + +#### send`_`init`_`chain + +```python +def send_init_chain( + request: abci_types.RequestInitChain) -> abci_types.ResponseInitChain +``` + +Sends an initChain request. + +:param: request: RequestInitChain pb object +:return: ResponseInitChain pb object + + + + +#### send`_`begin`_`block + +```python +def send_begin_block( + request: abci_types.RequestBeginBlock +) -> abci_types.ResponseBeginBlock +``` + +Sends an beginBlock request. + +:param: request: RequestBeginBlock pb object +:return: ResponseBeginBlock pb object + + + + +#### send`_`end`_`block + +```python +def send_end_block( + request: abci_types.RequestEndBlock) -> abci_types.ResponseEndBlock +``` + +Sends an endBlock request. + +:param: request: RequestEndBlock pb object +:return: ResponseEndBlock pb object + + + + +#### send`_`list`_`snapshots + +```python +def send_list_snapshots( + request: abci_types.RequestListSnapshots +) -> abci_types.ResponseListSnapshots +``` + +Sends an listSnapshots request. + +:param: request: RequestListSnapshots pb object +:return: ResponseListSnapshots pb object + + + + +#### send`_`offer`_`snapshot + +```python +def send_offer_snapshot( + request: abci_types.RequestOfferSnapshot +) -> abci_types.ResponseOfferSnapshot +``` + +Sends an offerSnapshot request. + +:param: request: RequestOfferSnapshot pb object +:return: ResponseOfferSnapshot pb object + + + + +#### send`_`load`_`snapshot`_`chunk + +```python +def send_load_snapshot_chunk( + request: abci_types.RequestLoadSnapshotChunk +) -> abci_types.ResponseLoadSnapshotChunk +``` + +Sends an loadSnapshotChunk request. + +:param: request: RequestLoadSnapshotChunk pb object +:return: ResponseLoadSnapshotChunk pb object + + + + +#### send`_`apply`_`snapshot`_`chunk + +```python +def send_apply_snapshot_chunk( + request: abci_types.RequestApplySnapshotChunk +) -> abci_types.ResponseApplySnapshotChunk +``` + +Sends an applySnapshotChunk request. + +:param: request: RequestApplySnapshotChunk pb object +:return: ResponseApplySnapshotChunk pb object + + diff --git a/docs/api/contracts/gnosis_safe/contract.md b/docs/api/contracts/gnosis_safe/contract.md index e733508472..23fc1a6c46 100644 --- a/docs/api/contracts/gnosis_safe/contract.md +++ b/docs/api/contracts/gnosis_safe/contract.md @@ -143,6 +143,18 @@ Note, because safe_nonce is included in the tx_hash the agents implicitly agree the hash of the raw Safe transaction + + +#### get`_`packed`_`signatures + +```python +@classmethod +def get_packed_signatures(cls, owners: Tuple[str], + signatures_by_owner: Dict[str, str]) -> bytes +``` + +Get the packed signatures. + #### get`_`raw`_`safe`_`transaction @@ -535,3 +547,15 @@ Get the safe owners. the safe owners + + +#### get`_`approve`_`hash`_`tx + +```python +@classmethod +def get_approve_hash_tx(cls, ledger_api: EthereumApi, contract_address: str, + tx_hash: str, sender: str) -> JSONLike +``` + +Get approve has tx. + diff --git a/docs/api/contracts/gnosis_safe/encode.md b/docs/api/contracts/gnosis_safe/encode.md new file mode 100644 index 0000000000..9df88feb46 --- /dev/null +++ b/docs/api/contracts/gnosis_safe/encode.md @@ -0,0 +1,140 @@ + + +# packages.valory.contracts.gnosis`_`safe.encode + +ETH encoder. + + + +#### encode + +```python +def encode(typ: t.Any, arg: t.Any) -> bytes +``` + +Encode by type. + + + +#### to`_`string + +```python +def to_string(value: t.Union[bytes, str, int]) -> bytes +``` + +Convert to byte string. + + + +#### sha3`_`256 + +```python +def sha3_256(x: bytes) -> bytes +``` + +Calculate SHA3-256 hash. + + + +#### sha3 + +```python +def sha3(seed: t.Union[bytes, str, int]) -> bytes +``` + +Calculate SHA3-256 hash. + + + +#### scan`_`bin + +```python +def scan_bin(v: str) -> bytes +``` + +Scan bytes. + + + +#### create`_`struct`_`definition + +```python +def create_struct_definition(name: str, schema: t.List[t.Dict[str, + str]]) -> str +``` + +Create method struction defintion. + + + +#### find`_`dependencies + +```python +def find_dependencies(name: str, types: t.Dict[str, t.Any], + dependencies: t.Set) -> None +``` + +Find dependencies. + + + +#### create`_`schema + +```python +def create_schema(name: str, types: t.Dict) -> str +``` + +Create schema. + + + +#### create`_`schema`_`hash + +```python +def create_schema_hash(name: str, types: t.Dict) -> bytes +``` + +Create schema hash. + + + +#### encode`_`value + +```python +def encode_value(data_type: str, value: t.Any, types: t.Dict) -> bytes +``` + +Encode value. + + + +#### encode`_`data + +```python +def encode_data(name: str, data: t.Dict[str, t.Dict[str, str]], + types: t.Dict) -> bytes +``` + +Encode data. + + + +#### create`_`struct`_`hash + +```python +def create_struct_hash(name: str, data: t.Dict[str, t.Dict[str, str]], + types: t.Dict) -> bytes +``` + +Create struct hash. + + + +#### encode`_`typed`_`data + +```python +def encode_typed_data(data: t.Dict[str, t.Any]) -> bytes +``` + +Encode typed data. + diff --git a/docs/api/data/Dockerfiles/dev/watcher.md b/docs/api/data/Dockerfiles/dev/watcher.md index 8e397c5e05..aafc13c6a3 100644 --- a/docs/api/data/Dockerfiles/dev/watcher.md +++ b/docs/api/data/Dockerfiles/dev/watcher.md @@ -38,6 +38,12 @@ class AEARunner() AEA Runner. + + +#### process + +nosec + #### `__`init`__` diff --git a/docs/api/data/contracts/agent_registry/contract.md b/docs/api/data/contracts/agent_registry/contract.md new file mode 100644 index 0000000000..17278d3de8 --- /dev/null +++ b/docs/api/data/contracts/agent_registry/contract.md @@ -0,0 +1,88 @@ + + +# autonomy.data.contracts.agent`_`registry.contract + +This module contains the class to connect to the Service Registry contract. + + + +## AgentRegistryContract Objects + +```python +class AgentRegistryContract(Contract) +``` + +The Agent Registry contract. + + + +#### get`_`raw`_`transaction + +```python +@classmethod +def get_raw_transaction(cls, ledger_api: LedgerApi, contract_address: str, + **kwargs: Any) -> Optional[JSONLike] +``` + +Get the Safe transaction. + + + +#### get`_`raw`_`message + +```python +@classmethod +def get_raw_message(cls, ledger_api: LedgerApi, contract_address: str, + **kwargs: Any) -> Optional[bytes] +``` + +Get raw message. + + + +#### get`_`state + +```python +@classmethod +def get_state(cls, ledger_api: LedgerApi, contract_address: str, + **kwargs: Any) -> Optional[JSONLike] +``` + +Get state. + + + +#### get`_`create`_`events + +```python +@classmethod +def get_create_events(cls, ledger_api: LedgerApi, contract_address: str, + receipt: JSONLike) -> Optional[int] +``` + +Returns `CreateUnit` event filter. + + + +#### get`_`update`_`hash`_`events + +```python +@classmethod +def get_update_hash_events(cls, ledger_api: LedgerApi, contract_address: str, + receipt: JSONLike) -> Optional[int] +``` + +Returns `CreateUnit` event filter. + + + +#### get`_`token`_`uri + +```python +@classmethod +def get_token_uri(cls, ledger_api: LedgerApi, contract_address: str, + token_id: int) -> str +``` + +Returns the latest metadata URI for a component. + diff --git a/docs/api/data/contracts/component_registry/contract.md b/docs/api/data/contracts/component_registry/contract.md new file mode 100644 index 0000000000..95455a139b --- /dev/null +++ b/docs/api/data/contracts/component_registry/contract.md @@ -0,0 +1,88 @@ + + +# autonomy.data.contracts.component`_`registry.contract + +This module contains the class to connect to the Service Registry contract. + + + +## ComponentRegistryContract Objects + +```python +class ComponentRegistryContract(Contract) +``` + +The Service Registry contract. + + + +#### get`_`raw`_`transaction + +```python +@classmethod +def get_raw_transaction(cls, ledger_api: LedgerApi, contract_address: str, + **kwargs: Any) -> Optional[JSONLike] +``` + +Get the Safe transaction. + + + +#### get`_`raw`_`message + +```python +@classmethod +def get_raw_message(cls, ledger_api: LedgerApi, contract_address: str, + **kwargs: Any) -> Optional[bytes] +``` + +Get raw message. + + + +#### get`_`state + +```python +@classmethod +def get_state(cls, ledger_api: LedgerApi, contract_address: str, + **kwargs: Any) -> Optional[JSONLike] +``` + +Get state. + + + +#### get`_`create`_`events + +```python +@classmethod +def get_create_events(cls, ledger_api: LedgerApi, contract_address: str, + receipt: JSONLike) -> Optional[int] +``` + +Returns `CreateUnit` event filter. + + + +#### get`_`update`_`hash`_`events + +```python +@classmethod +def get_update_hash_events(cls, ledger_api: LedgerApi, contract_address: str, + receipt: JSONLike) -> Optional[int] +``` + +Returns `CreateUnit` event filter. + + + +#### get`_`token`_`uri + +```python +@classmethod +def get_token_uri(cls, ledger_api: LedgerApi, contract_address: str, + token_id: int) -> str +``` + +Returns the latest metadata URI for a component. + diff --git a/docs/api/data/contracts/erc20/contract.md b/docs/api/data/contracts/erc20/contract.md new file mode 100644 index 0000000000..bce91279bf --- /dev/null +++ b/docs/api/data/contracts/erc20/contract.md @@ -0,0 +1,115 @@ + + +# autonomy.data.contracts.erc20.contract + +This module contains the scaffold contract definition. + + + +## ERC20TokenContract Objects + +```python +class ERC20TokenContract(Contract) +``` + +ERC20 token contract. + + + +#### get`_`raw`_`transaction + +```python +@classmethod +def get_raw_transaction(cls, ledger_api: LedgerApi, contract_address: str, + **kwargs: Any) -> JSONLike +``` + +Handler method for the 'GET_RAW_TRANSACTION' requests. + +Implement this method in the sub class if you want +to handle the contract requests manually. + +**Arguments**: + +- `ledger_api`: the ledger apis. +- `contract_address`: the contract address. +- `kwargs`: the keyword arguments. + +**Returns**: + +the tx # noqa: DAR202 + + + +#### get`_`raw`_`message + +```python +@classmethod +def get_raw_message(cls, ledger_api: LedgerApi, contract_address: str, + **kwargs: Any) -> bytes +``` + +Handler method for the 'GET_RAW_MESSAGE' requests. + +Implement this method in the sub class if you want +to handle the contract requests manually. + +**Arguments**: + +- `ledger_api`: the ledger apis. +- `contract_address`: the contract address. +- `kwargs`: the keyword arguments. + +**Returns**: + +the tx # noqa: DAR202 + + + +#### get`_`state + +```python +@classmethod +def get_state(cls, ledger_api: LedgerApi, contract_address: str, + **kwargs: Any) -> JSONLike +``` + +Handler method for the 'GET_STATE' requests. + +Implement this method in the sub class if you want +to handle the contract requests manually. + +**Arguments**: + +- `ledger_api`: the ledger apis. +- `contract_address`: the contract address. +- `kwargs`: the keyword arguments. + +**Returns**: + +the tx # noqa: DAR202 + + + +#### get`_`approve`_`tx + +```python +@classmethod +def get_approve_tx(cls, ledger_api: LedgerApi, contract_address: str, + spender: str, amount: int, sender: str) -> JSONLike +``` + +Get approve tx. + + + +#### get`_`approval`_`events + +```python +@classmethod +def get_approval_events(cls, ledger_api: LedgerApi, contract_address: str, + tx_receipt: JSONLike) -> JSONLike +``` + +Get approve tx. + diff --git a/docs/api/data/contracts/gnosis_safe/contract.md b/docs/api/data/contracts/gnosis_safe/contract.md new file mode 100644 index 0000000000..35a001de12 --- /dev/null +++ b/docs/api/data/contracts/gnosis_safe/contract.md @@ -0,0 +1,561 @@ + + +# autonomy.data.contracts.gnosis`_`safe.contract + +This module contains the class to connect to an Gnosis Safe contract. + + + +#### checksum`_`address + +```python +def checksum_address(agent_address: str) -> ChecksumAddress +``` + +Get the checksum address. + + + +## SafeOperation Objects + +```python +class SafeOperation(Enum) +``` + +Operation types. + + + +## GnosisSafeContract Objects + +```python +class GnosisSafeContract(Contract) +``` + +The Gnosis Safe contract. + + + +#### get`_`raw`_`transaction + +```python +@classmethod +def get_raw_transaction(cls, ledger_api: LedgerApi, contract_address: str, + **kwargs: Any) -> Optional[JSONLike] +``` + +Get the Safe transaction. + + + +#### get`_`raw`_`message + +```python +@classmethod +def get_raw_message(cls, ledger_api: LedgerApi, contract_address: str, + **kwargs: Any) -> Optional[bytes] +``` + +Get raw message. + + + +#### get`_`state + +```python +@classmethod +def get_state(cls, ledger_api: LedgerApi, contract_address: str, + **kwargs: Any) -> Optional[JSONLike] +``` + +Get state. + + + +#### get`_`deploy`_`transaction + +```python +@classmethod +def get_deploy_transaction(cls, ledger_api: LedgerApi, deployer_address: str, + **kwargs: Any) -> Optional[JSONLike] +``` + +Get deploy transaction. + +**Arguments**: + +- `ledger_api`: ledger API object. +- `deployer_address`: the deployer address. +- `kwargs`: the keyword arguments. + +**Returns**: + +an optional JSON-like object. + + + +#### get`_`raw`_`safe`_`transaction`_`hash + +```python +@classmethod +def get_raw_safe_transaction_hash(cls, + ledger_api: EthereumApi, + contract_address: str, + to_address: str, + value: int, + data: bytes, + operation: int = SafeOperation.CALL.value, + safe_tx_gas: int = 0, + base_gas: int = 0, + gas_price: int = 0, + gas_token: str = NULL_ADDRESS, + refund_receiver: str = NULL_ADDRESS, + safe_nonce: Optional[int] = None, + safe_version: Optional[str] = None, + chain_id: Optional[int] = None) -> JSONLike +``` + +Get the hash of the raw Safe transaction. + +Adapted from https://github.com/gnosis/gnosis-py/blob/69f1ee3263086403f6017effa0841c6a2fbba6d6/gnosis/safe/safe_tx.py#L125 + +Note, because safe_nonce is included in the tx_hash the agents implicitly agree on the order of txs if they agree on a tx_hash. + +**Arguments**: + +- `ledger_api`: the ledger API object +- `contract_address`: the contract address +- `to_address`: the tx recipient address +- `value`: the ETH value of the transaction +- `data`: the data of the transaction +- `operation`: Operation type of Safe transaction +- `safe_tx_gas`: Gas that should be used for the Safe transaction +- `base_gas`: Gas costs for that are independent of the transaction execution +(e.g. base transaction fee, signature check, payment of the refund) +- `gas_price`: Gas price that should be used for the payment calculation +- `gas_token`: Token address (or `0x000..000` if ETH) that is used for the payment +- `refund_receiver`: Address of receiver of gas payment (or `0x000..000` if tx.origin). +- `safe_nonce`: Current nonce of the Safe. If not provided, it will be retrieved from network +- `safe_version`: Safe version 1.0.0 renamed `baseGas` to `dataGas`. Safe version 1.3.0 added `chainId` to the `domainSeparator`. If not provided, it will be retrieved from network +- `chain_id`: Ethereum network chain_id is used in hash calculation for Safes >= 1.3.0. If not provided, it will be retrieved from the provided ethereum_client + +**Returns**: + +the hash of the raw Safe transaction + + + +#### get`_`packed`_`signatures + +```python +@classmethod +def get_packed_signatures(cls, owners: Tuple[str], + signatures_by_owner: Dict[str, str]) -> bytes +``` + +Get the packed signatures. + + + +#### get`_`raw`_`safe`_`transaction + +```python +@classmethod +def get_raw_safe_transaction(cls, + ledger_api: EthereumApi, + contract_address: str, + sender_address: str, + owners: Tuple[str], + to_address: str, + value: int, + data: bytes, + signatures_by_owner: Dict[str, str], + operation: int = SafeOperation.CALL.value, + safe_tx_gas: int = 0, + base_gas: int = 0, + safe_gas_price: int = 0, + gas_token: str = NULL_ADDRESS, + refund_receiver: str = NULL_ADDRESS, + gas_price: Optional[int] = None, + nonce: Optional[Nonce] = None, + max_fee_per_gas: Optional[int] = None, + max_priority_fee_per_gas: Optional[int] = None, + old_price: Optional[Dict[str, Wei]] = None, + fallback_gas: int = 0) -> JSONLike +``` + +Get the raw Safe transaction + +**Arguments**: + +- `ledger_api`: the ledger API object +- `contract_address`: the contract address +- `sender_address`: the address of the sender +- `owners`: the sequence of owners +- `to_address`: Destination address of Safe transaction +- `value`: Ether value of Safe transaction +- `data`: Data payload of Safe transaction +- `signatures_by_owner`: mapping from owners to signatures +- `operation`: Operation type of Safe transaction +- `safe_tx_gas`: Gas that should be used for the Safe transaction +- `base_gas`: Gas costs for that are independent of the transaction execution +(e.g. base transaction fee, signature check, payment of the refund) +- `safe_gas_price`: Gas price that should be used for the payment calculation +- `gas_token`: Token address (or `0x000..000` if ETH) that is used for the payment +- `refund_receiver`: Address of receiver of gas payment (or `0x000..000` if tx.origin). +- `gas_price`: gas price +- `nonce`: the nonce +- `max_fee_per_gas`: max +- `max_priority_fee_per_gas`: max +- `old_price`: the old gas price params in case that we are trying to resubmit a transaction. +- `fallback_gas`: (external) gas to spend when base_gas and safe_tx_gas are zero and no gas estimation is possible. + +**Returns**: + +the raw Safe transaction + + + +#### verify`_`contract + +```python +@classmethod +def verify_contract(cls, ledger_api: LedgerApi, + contract_address: str) -> JSONLike +``` + +Verify the contract's bytecode + +**Arguments**: + +- `ledger_api`: the ledger API object +- `contract_address`: the contract address + +**Returns**: + +the verified status + + + +#### verify`_`tx + +```python +@classmethod +def verify_tx(cls, + ledger_api: EthereumApi, + contract_address: str, + tx_hash: str, + owners: Tuple[str], + to_address: str, + value: int, + data: bytes, + signatures_by_owner: Dict[str, str], + operation: int = SafeOperation.CALL.value, + safe_tx_gas: int = 0, + base_gas: int = 0, + gas_price: int = 0, + gas_token: str = NULL_ADDRESS, + refund_receiver: str = NULL_ADDRESS, + safe_version: Optional[str] = None) -> JSONLike +``` + +Verify a tx hash exists on the blockchain. + +Currently, the implementation is an overkill as most of the verification is implicit by the acceptance of the transaction in the Safe. + +**Arguments**: + +- `ledger_api`: the ledger API object +- `contract_address`: the contract address +- `tx_hash`: the transaction hash +- `owners`: the sequence of owners +- `to_address`: Destination address of Safe transaction +- `value`: Ether value of Safe transaction +- `data`: Data payload of Safe transaction +- `signatures_by_owner`: mapping from owners to signatures +- `operation`: Operation type of Safe transaction +- `safe_tx_gas`: Gas that should be used for the Safe transaction +- `base_gas`: Gas costs for that are independent of the transaction execution +(e.g. base transaction fee, signature check, payment of the refund) +- `gas_price`: Gas price that should be used for the payment calculation +- `gas_token`: Token address (or `0x000..000` if ETH) that is used for the payment +- `refund_receiver`: Address of receiver of gas payment (or `0x000..000` if tx.origin). +- `safe_version`: Safe version 1.0.0 renamed `baseGas` to `dataGas`. Safe version 1.3.0 added `chainId` to the `domainSeparator`. If not provided, it will be retrieved from network + +**Returns**: + +the verified status + + + +#### revert`_`reason + +```python +@classmethod +def revert_reason(cls, ledger_api: EthereumApi, contract_address: str, + tx: TxData) -> JSONLike +``` + +Check the revert reason of a transaction. + +**Arguments**: + +- `ledger_api`: the ledger API object. +- `contract_address`: the contract address +- `tx`: the transaction for which we want to get the revert reason. + +**Returns**: + +the revert reason message. + + + +#### get`_`safe`_`nonce + +```python +@classmethod +def get_safe_nonce(cls, ledger_api: EthereumApi, + contract_address: str) -> JSONLike +``` + +Retrieve the safe's nonce + +**Arguments**: + +- `ledger_api`: the ledger API object +- `contract_address`: the contract address + +**Returns**: + +the safe nonce + + + +#### get`_`ingoing`_`transfers + +```python +@classmethod +def get_ingoing_transfers(cls, + ledger_api: EthereumApi, + contract_address: str, + from_block: Optional[str] = None, + to_block: Optional[str] = "latest") -> JSONLike +``` + +A list of transfers into the contract. + +**Arguments**: + +- `ledger_api`: the ledger API object +- `contract_address`: the contract address, +- `from_block`: from which block to start tje search +- `to_block`: at which block to end the search + +**Returns**: + +list of transfers + + + +#### get`_`balance + +```python +@classmethod +def get_balance(cls, ledger_api: EthereumApi, + contract_address: str) -> JSONLike +``` + +Retrieve the safe's balance + +**Arguments**: + +- `ledger_api`: the ledger API object +- `contract_address`: the contract address + +**Returns**: + +the safe balance (in wei) + + + +#### get`_`amount`_`spent + +```python +@classmethod +def get_amount_spent(cls, ledger_api: EthereumApi, contract_address: str, + tx_hash: str) -> JSONLike +``` + +Get the amount of ether spent in a tx. + +**Arguments**: + +- `ledger_api`: the ledger API object +- `contract_address`: the contract address (not used) +- `tx_hash`: the settled tx hash + +**Returns**: + +the safe balance (in wei) + + + +#### get`_`safe`_`txs + +```python +@classmethod +def get_safe_txs(cls, + ledger_api: EthereumApi, + contract_address: str, + from_block: BlockIdentifier = "earliest", + to_block: BlockIdentifier = "latest") -> JSONLike +``` + +Get all the safe tx hashes. + +**Arguments**: + +- `ledger_api`: the ledger API object +- `contract_address`: the contract address (not used) +- `from_block`: from which block to search for events +- `to_block`: to which block to search for events +:return: the safe txs + + + +#### get`_`removed`_`owner`_`events + +```python +@classmethod +def get_removed_owner_events(cls, + ledger_api: EthereumApi, + contract_address: str, + removed_owner: Optional[str] = None, + from_block: BlockIdentifier = "earliest", + to_block: BlockIdentifier = "latest") -> JSONLike +``` + +Get all RemovedOwner events for a safe contract. + +**Arguments**: + +- `ledger_api`: the ledger API object +- `contract_address`: the contract address +- `removed_owner`: the owner to check for, any owner qualifies if not provided. +- `from_block`: from which block to search for events +- `to_block`: to which block to search for events + +**Returns**: + +the added owner events + + + +#### get`_`zero`_`transfer`_`events + +```python +@classmethod +def get_zero_transfer_events(cls, + ledger_api: EthereumApi, + contract_address: str, + sender_address: str, + from_block: BlockIdentifier = "earliest", + to_block: BlockIdentifier = "latest") -> JSONLike +``` + +Get all zero transfer events from a given sender to the safe address. + +**Arguments**: + +- `ledger_api`: the ledger API object +- `contract_address`: the contract address +- `sender_address`: the owner of the service, ie the address that triggers termination +- `from_block`: from which block to search for events +- `to_block`: to which block to search for events +:return: the zero transfer events + + + +#### get`_`remove`_`owner`_`data + +```python +@classmethod +def get_remove_owner_data(cls, ledger_api: EthereumApi, contract_address: str, + owner: str, threshold: int) -> JSONLike +``` + +Get a removeOwner() encoded tx. + +This method acts as a wrapper for `removeOwner()` +https://github.com/safe-global/safe-contracts/blob/v1.3.0/contracts/base/OwnerManager.sol#L70 + +**Arguments**: + +- `ledger_api`: the ledger API object +- `contract_address`: the contract address +- `owner`: the owner to be removed +- `threshold`: the new safe threshold to be set + +**Returns**: + +the zero transfer events + + + +#### get`_`swap`_`owner`_`data + +```python +@classmethod +def get_swap_owner_data(cls, ledger_api: EthereumApi, contract_address: str, + old_owner: str, new_owner: str) -> JSONLike +``` + +Get a swapOwner() encoded tx. + +This method acts as a wrapper for `swapOwner()` +https://github.com/safe-global/safe-contracts/blob/v1.3.0/contracts/base/OwnerManager.sol#L94 + +**Arguments**: + +- `ledger_api`: the ledger API object +- `contract_address`: the contract address +- `old_owner`: the owner to be replaced +- `new_owner`: owner to replace old_owner + +**Returns**: + +the zero transfer events + + + +#### get`_`owners + +```python +@classmethod +def get_owners(cls, ledger_api: EthereumApi, + contract_address: str) -> JSONLike +``` + +Get the safe owners. + +**Arguments**: + +- `ledger_api`: the ledger API object +- `contract_address`: the contract address + +**Returns**: + +the safe owners + + + +#### get`_`approve`_`hash`_`tx + +```python +@classmethod +def get_approve_hash_tx(cls, ledger_api: EthereumApi, contract_address: str, + tx_hash: str, sender: str) -> JSONLike +``` + +Get approve has tx. + diff --git a/docs/api/data/contracts/gnosis_safe/encode.md b/docs/api/data/contracts/gnosis_safe/encode.md new file mode 100644 index 0000000000..96c8383a92 --- /dev/null +++ b/docs/api/data/contracts/gnosis_safe/encode.md @@ -0,0 +1,140 @@ + + +# autonomy.data.contracts.gnosis`_`safe.encode + +ETH encoder. + + + +#### encode + +```python +def encode(typ: t.Any, arg: t.Any) -> bytes +``` + +Encode by type. + + + +#### to`_`string + +```python +def to_string(value: t.Union[bytes, str, int]) -> bytes +``` + +Convert to byte string. + + + +#### sha3`_`256 + +```python +def sha3_256(x: bytes) -> bytes +``` + +Calculate SHA3-256 hash. + + + +#### sha3 + +```python +def sha3(seed: t.Union[bytes, str, int]) -> bytes +``` + +Calculate SHA3-256 hash. + + + +#### scan`_`bin + +```python +def scan_bin(v: str) -> bytes +``` + +Scan bytes. + + + +#### create`_`struct`_`definition + +```python +def create_struct_definition(name: str, schema: t.List[t.Dict[str, + str]]) -> str +``` + +Create method struction defintion. + + + +#### find`_`dependencies + +```python +def find_dependencies(name: str, types: t.Dict[str, t.Any], + dependencies: t.Set) -> None +``` + +Find dependencies. + + + +#### create`_`schema + +```python +def create_schema(name: str, types: t.Dict) -> str +``` + +Create schema. + + + +#### create`_`schema`_`hash + +```python +def create_schema_hash(name: str, types: t.Dict) -> bytes +``` + +Create schema hash. + + + +#### encode`_`value + +```python +def encode_value(data_type: str, value: t.Any, types: t.Dict) -> bytes +``` + +Encode value. + + + +#### encode`_`data + +```python +def encode_data(name: str, data: t.Dict[str, t.Dict[str, str]], + types: t.Dict) -> bytes +``` + +Encode data. + + + +#### create`_`struct`_`hash + +```python +def create_struct_hash(name: str, data: t.Dict[str, t.Dict[str, str]], + types: t.Dict) -> bytes +``` + +Create struct hash. + + + +#### encode`_`typed`_`data + +```python +def encode_typed_data(data: t.Dict[str, t.Any]) -> bytes +``` + +Encode typed data. + diff --git a/docs/api/data/contracts/gnosis_safe_proxy_factory/contract.md b/docs/api/data/contracts/gnosis_safe_proxy_factory/contract.md new file mode 100644 index 0000000000..20cd6e1fd9 --- /dev/null +++ b/docs/api/data/contracts/gnosis_safe_proxy_factory/contract.md @@ -0,0 +1,136 @@ + + +# autonomy.data.contracts.gnosis`_`safe`_`proxy`_`factory.contract + +This module contains the class to connect to an Gnosis Safe Proxy Factory contract. + + + +## GnosisSafeProxyFactoryContract Objects + +```python +class GnosisSafeProxyFactoryContract(Contract) +``` + +The Gnosis Safe Proxy Factory contract. + + + +#### get`_`raw`_`transaction + +```python +@classmethod +def get_raw_transaction(cls, ledger_api: LedgerApi, contract_address: str, + **kwargs: Any) -> Optional[JSONLike] +``` + +Get the raw transaction. + + + +#### get`_`raw`_`message + +```python +@classmethod +def get_raw_message(cls, ledger_api: LedgerApi, contract_address: str, + **kwargs: Any) -> Optional[bytes] +``` + +Get raw message. + + + +#### get`_`state + +```python +@classmethod +def get_state(cls, ledger_api: LedgerApi, contract_address: str, + **kwargs: Any) -> Optional[JSONLike] +``` + +Get state. + + + +#### get`_`deploy`_`transaction + +```python +@classmethod +def get_deploy_transaction(cls, ledger_api: LedgerApi, deployer_address: str, + **kwargs: Any) -> Optional[JSONLike] +``` + +Get deploy transaction. + +**Arguments**: + +- `ledger_api`: ledger API object. +- `deployer_address`: the deployer address. +- `kwargs`: the keyword arguments. + +**Returns**: + +an optional JSON-like object. + + + +#### build`_`tx`_`deploy`_`proxy`_`contract`_`with`_`nonce + +```python +@classmethod +def build_tx_deploy_proxy_contract_with_nonce( + cls, + ledger_api: EthereumApi, + proxy_factory_address: str, + master_copy: str, + address: str, + initializer: bytes, + salt_nonce: int, + gas: int = MIN_GAS, + gas_price: Optional[int] = None, + max_fee_per_gas: Optional[int] = None, + max_priority_fee_per_gas: Optional[int] = None, + nonce: Optional[int] = None) -> Tuple[TxParams, str] +``` + +Deploy proxy contract via Proxy Factory using `createProxyWithNonce` (create2) + +**Arguments**: + +- `ledger_api`: ledger API object +- `proxy_factory_address`: the address of the proxy factory +- `address`: Ethereum address +- `master_copy`: Address the proxy will point at +- `initializer`: Data for safe creation +- `salt_nonce`: Uint256 for `create2` salt +- `gas`: Gas +- `gas_price`: Gas Price +- `max_fee_per_gas`: max +- `max_priority_fee_per_gas`: max +- `nonce`: Nonce + +**Returns**: + +Tuple(tx-hash, tx, deployed contract address) + + + +#### verify`_`contract + +```python +@classmethod +def verify_contract(cls, ledger_api: EthereumApi, + contract_address: str) -> JSONLike +``` + +Verify the contract's bytecode + +**Arguments**: + +- `ledger_api`: the ledger API object +- `contract_address`: the contract address + +**Returns**: + +the verified status + diff --git a/docs/api/data/contracts/multisend/contract.md b/docs/api/data/contracts/multisend/contract.md new file mode 100644 index 0000000000..9fe5e64c39 --- /dev/null +++ b/docs/api/data/contracts/multisend/contract.md @@ -0,0 +1,180 @@ + + +# autonomy.data.contracts.multisend.contract + +This module contains the class to connect to an Gnosis Safe contract. + + + +## MultiSendOperation Objects + +```python +class MultiSendOperation(Enum) +``` + +Operation types. + + + +#### encode`_`data + +```python +def encode_data(tx: Dict) -> bytes +``` + +Encodes multisend transaction. + + + +#### decode`_`data + +```python +def decode_data(encoded_tx: bytes) -> Tuple[Dict, int] +``` + +Decodes multisend transaction. + + + +#### to`_`bytes + +```python +def to_bytes(multi_send_txs: List[Dict]) -> bytes +``` + +Multi send tx list to bytes. + + + +#### from`_`bytes + +```python +def from_bytes(encoded_multisend_txs: bytes) -> List[Dict] +``` + +Encoded multi send tx to list. + + + +## MultiSendContract Objects + +```python +class MultiSendContract(Contract) +``` + +The MultiSend contract. + + + +#### get`_`raw`_`transaction + +```python +@classmethod +def get_raw_transaction(cls, ledger_api: LedgerApi, contract_address: str, + **kwargs: Any) -> Optional[JSONLike] +``` + +Get the Safe transaction. + + + +#### get`_`raw`_`message + +```python +@classmethod +def get_raw_message(cls, ledger_api: LedgerApi, contract_address: str, + **kwargs: Any) -> Optional[bytes] +``` + +Get raw message. + + + +#### get`_`state + +```python +@classmethod +def get_state(cls, ledger_api: LedgerApi, contract_address: str, + **kwargs: Any) -> Optional[JSONLike] +``` + +Get state. + + + +#### get`_`deploy`_`transaction + +```python +@classmethod +def get_deploy_transaction(cls, ledger_api: LedgerApi, deployer_address: str, + **kwargs: Any) -> Optional[JSONLike] +``` + +Get deploy transaction. + + + +#### get`_`tx`_`data + +```python +@classmethod +def get_tx_data(cls, ledger_api: LedgerApi, contract_address: str, + multi_send_txs: List[Dict]) -> Optional[JSONLike] +``` + +Get a multisend transaction data from list. + +**Arguments**: + +- `ledger_api`: ledger API object. +- `contract_address`: the contract address. +- `multi_send_txs`: the multisend transaction list. + +**Returns**: + +an optional JSON-like object. + + + +#### get`_`multisend`_`tx + +```python +@classmethod +def get_multisend_tx(cls, ledger_api: LedgerApi, contract_address: str, + txs: List[Dict]) -> Optional[JSONLike] +``` + +Get a multisend transaction data from list. + +**Arguments**: + +- `ledger_api`: ledger API object. +- `contract_address`: the contract address. +- `txs`: the multisend transaction list. + +**Returns**: + +an optional JSON-like object. + + + +#### get`_`tx`_`list + +```python +@classmethod +def get_tx_list(cls, ledger_api: LedgerApi, contract_address: str, + multi_send_data: str) -> Optional[JSONLike] +``` + +Get a multisend transaction list from encoded data. + +**Arguments**: + +- `ledger_api`: ledger API object. +- `contract_address`: the contract address. +- `multi_send_data`: the multisend transaction data. + +**Returns**: + +an optional JSON-like object. + diff --git a/docs/api/data/contracts/registries_manager/contract.md b/docs/api/data/contracts/registries_manager/contract.md new file mode 100644 index 0000000000..eb0de726fa --- /dev/null +++ b/docs/api/data/contracts/registries_manager/contract.md @@ -0,0 +1,99 @@ + + +# autonomy.data.contracts.registries`_`manager.contract + +This module contains the class to connect to the Service Registry contract. + + + +## RegistriesManagerContract Objects + +```python +class RegistriesManagerContract(Contract) +``` + +The Service Registry contract. + + + +## UnitType Objects + +```python +class UnitType(Enum) +``` + +Unit type. + + + +#### get`_`raw`_`transaction + +```python +@classmethod +def get_raw_transaction(cls, ledger_api: LedgerApi, contract_address: str, + **kwargs: Any) -> Optional[JSONLike] +``` + +Get the Safe transaction. + + + +#### get`_`raw`_`message + +```python +@classmethod +def get_raw_message(cls, ledger_api: LedgerApi, contract_address: str, + **kwargs: Any) -> Optional[bytes] +``` + +Get raw message. + + + +#### get`_`state + +```python +@classmethod +def get_state(cls, ledger_api: LedgerApi, contract_address: str, + **kwargs: Any) -> Optional[JSONLike] +``` + +Get state. + + + +#### get`_`create`_`transaction + +```python +@classmethod +def get_create_transaction(cls, + ledger_api: LedgerApi, + contract_address: str, + component_type: UnitType, + metadata_hash: str, + owner: str, + sender: str, + dependencies: Optional[List[int]] = None, + raise_on_try: bool = False) -> JSONLike +``` + +Create a component. + + + +#### get`_`update`_`hash`_`transaction + +```python +@classmethod +def get_update_hash_transaction(cls, + ledger_api: LedgerApi, + contract_address: str, + component_type: UnitType, + unit_id: int, + metadata_hash: str, + sender: str, + raise_on_try: bool = False) -> JSONLike +``` + +Create a component. + diff --git a/docs/api/data/contracts/service_manager/contract.md b/docs/api/data/contracts/service_manager/contract.md new file mode 100644 index 0000000000..59674c4106 --- /dev/null +++ b/docs/api/data/contracts/service_manager/contract.md @@ -0,0 +1,220 @@ + + +# autonomy.data.contracts.service`_`manager.contract + +This module contains the class to connect to the Service Registry contract. + + + +## ServiceManagerContract Objects + +```python +class ServiceManagerContract(Contract) +``` + +The Service manager contract. + + + +#### get`_`raw`_`transaction + +```python +@classmethod +def get_raw_transaction(cls, ledger_api: LedgerApi, contract_address: str, + **kwargs: Any) -> Optional[JSONLike] +``` + +Get the Safe transaction. + + + +#### get`_`raw`_`message + +```python +@classmethod +def get_raw_message(cls, ledger_api: LedgerApi, contract_address: str, + **kwargs: Any) -> Optional[bytes] +``` + +Get raw message. + + + +#### get`_`state + +```python +@classmethod +def get_state(cls, ledger_api: LedgerApi, contract_address: str, + **kwargs: Any) -> Optional[JSONLike] +``` + +Get state. + + + +#### load`_`l2`_`build + +```python +@staticmethod +def load_l2_build() -> JSONLike +``` + +Load L2 ABI + + + +#### is`_`l1`_`chain + +```python +@staticmethod +def is_l1_chain(ledger_api: LedgerApi) -> bool +``` + +Check if we're interecting with an L1 chain + + + +#### get`_`instance + +```python +@classmethod +def get_instance(cls, + ledger_api: LedgerApi, + contract_address: Optional[str] = None) -> Any +``` + +Get contract instance. + + + +#### get`_`create`_`transaction + +```python +@classmethod +def get_create_transaction(cls, + ledger_api: LedgerApi, + contract_address: str, + owner: str, + sender: str, + metadata_hash: str, + agent_ids: List[int], + agent_params: List[List[int]], + threshold: int, + token: Optional[str] = None, + raise_on_try: bool = False) -> Dict[str, Any] +``` + +Retrieve the service owner. + + + +#### get`_`update`_`transaction + +```python +@classmethod +def get_update_transaction(cls, + ledger_api: LedgerApi, + contract_address: str, + sender: str, + service_id: int, + metadata_hash: str, + agent_ids: List[int], + agent_params: List[List[int]], + threshold: int, + token: str = ETHEREUM_ERC20, + raise_on_try: bool = False) -> Dict[str, Any] +``` + +Retrieve the service owner. + + + +#### get`_`activate`_`registration`_`transaction + +```python +@classmethod +def get_activate_registration_transaction( + cls, + ledger_api: LedgerApi, + contract_address: str, + owner: str, + service_id: int, + security_deposit: int, + raise_on_try: bool = False) -> Dict[str, Any] +``` + +Retrieve the service owner. + + + +#### get`_`register`_`instance`_`transaction + +```python +@classmethod +def get_register_instance_transaction( + cls, + ledger_api: LedgerApi, + contract_address: str, + owner: str, + service_id: int, + instances: List[str], + agent_ids: List[int], + security_deposit: int, + raise_on_try: bool = False) -> Dict[str, Any] +``` + +Retrieve the service owner. + + + +#### get`_`service`_`deploy`_`transaction + +```python +@classmethod +def get_service_deploy_transaction( + cls, + ledger_api: LedgerApi, + contract_address: str, + owner: str, + service_id: int, + gnosis_safe_multisig: str, + deployment_payload: str, + raise_on_try: bool = False) -> Dict[str, Any] +``` + +Retrieve the service owner. + + + +#### get`_`terminate`_`service`_`transaction + +```python +@classmethod +def get_terminate_service_transaction( + cls, + ledger_api: LedgerApi, + contract_address: str, + owner: str, + service_id: int, + raise_on_try: bool = False) -> Dict[str, Any] +``` + +Retrieve the service owner. + + + +#### get`_`unbond`_`service`_`transaction + +```python +@classmethod +def get_unbond_service_transaction( + cls, + ledger_api: LedgerApi, + contract_address: str, + owner: str, + service_id: int, + raise_on_try: bool = False) -> Dict[str, Any] +``` + +Retrieve the service owner. + diff --git a/docs/api/data/contracts/service_registry/contract.md b/docs/api/data/contracts/service_registry/contract.md new file mode 100644 index 0000000000..9081f5a1ac --- /dev/null +++ b/docs/api/data/contracts/service_registry/contract.md @@ -0,0 +1,275 @@ + + +# autonomy.data.contracts.service`_`registry.contract + +This module contains the class to connect to the Service Registry contract. + + + +## ServiceRegistryContract Objects + +```python +class ServiceRegistryContract(Contract) +``` + +The Service Registry contract. + + + +#### get`_`raw`_`transaction + +```python +@classmethod +def get_raw_transaction(cls, ledger_api: LedgerApi, contract_address: str, + **kwargs: Any) -> Optional[JSONLike] +``` + +Get the Safe transaction. + + + +#### get`_`raw`_`message + +```python +@classmethod +def get_raw_message(cls, ledger_api: LedgerApi, contract_address: str, + **kwargs: Any) -> Optional[bytes] +``` + +Get raw message. + + + +#### get`_`state + +```python +@classmethod +def get_state(cls, ledger_api: LedgerApi, contract_address: str, + **kwargs: Any) -> Optional[JSONLike] +``` + +Get state. + + + +#### is`_`l1`_`chain + +```python +@staticmethod +def is_l1_chain(ledger_api: LedgerApi) -> bool +``` + +Check if we're interecting with an L1 chain + + + +#### load`_`l2`_`build + +```python +@staticmethod +def load_l2_build() -> JSONLike +``` + +Load L2 ABI + + + +#### get`_`instance + +```python +@classmethod +def get_instance(cls, + ledger_api: LedgerApi, + contract_address: Optional[str] = None) -> Any +``` + +Get contract instance. + + + +#### verify`_`contract + +```python +@classmethod +def verify_contract(cls, ledger_api: LedgerApi, + contract_address: str) -> Dict[str, Union[bool, str]] +``` + +Verify the contract's bytecode + +**Arguments**: + +- `ledger_api`: the ledger API object +- `contract_address`: the contract address + +**Returns**: + +the verified status + + + +#### exists + +```python +@classmethod +def exists(cls, ledger_api: LedgerApi, contract_address: str, + service_id: int) -> bool +``` + +Check if the service id exists + + + +#### get`_`agent`_`instances + +```python +@classmethod +def get_agent_instances(cls, ledger_api: LedgerApi, contract_address: str, + service_id: int) -> Dict[str, Any] +``` + +Retrieve on-chain agent instances. + + + +#### get`_`service`_`owner + +```python +@classmethod +def get_service_owner(cls, ledger_api: LedgerApi, contract_address: str, + service_id: int) -> Dict[str, Any] +``` + +Retrieve the service owner. + + + +#### get`_`service`_`information + +```python +@classmethod +def get_service_information(cls, ledger_api: LedgerApi, contract_address: str, + token_id: int) -> ServiceInfo +``` + +Retrieve service information + + + +#### get`_`token`_`uri + +```python +@classmethod +def get_token_uri(cls, ledger_api: LedgerApi, contract_address: str, + token_id: int) -> str +``` + +Returns the latest metadata URI for a component. + + + +#### get`_`create`_`events + +```python +@classmethod +def get_create_events(cls, ledger_api: LedgerApi, contract_address: str, + receipt: JSONLike) -> Optional[int] +``` + +Returns `CreateUnit` event filter. + + + +#### get`_`update`_`events + +```python +@classmethod +def get_update_events(cls, ledger_api: LedgerApi, contract_address: str, + receipt: JSONLike) -> Optional[int] +``` + +Returns `CreateUnit` event filter. + + + +#### get`_`update`_`hash`_`events + +```python +@classmethod +def get_update_hash_events(cls, ledger_api: LedgerApi, contract_address: str, + receipt: JSONLike) -> Optional[int] +``` + +Returns `CreateUnit` event filter. + + + +#### process`_`receipt + +```python +@classmethod +def process_receipt(cls, ledger_api: LedgerApi, contract_address: str, + event: str, receipt: JSONLike) -> JSONLike +``` + +Checks for a successful service registration event in the latest block + + + +#### get`_`slash`_`data + +```python +@classmethod +def get_slash_data(cls, ledger_api: LedgerApi, contract_address: str, + agent_instances: List[str], amounts: List[int], + service_id: int) -> Dict[str, bytes] +``` + +Gets the encoded arguments for a slashing tx, which should only be called via the multisig. + + + +#### process`_`slash`_`receipt + +```python +@classmethod +def process_slash_receipt(cls, ledger_api: LedgerApi, contract_address: str, + tx_hash: str) -> Optional[JSONLike] +``` + +Process the slash receipt. + +**Arguments**: + +- `ledger_api`: the ledger apis. +- `contract_address`: the contract address. +- `tx_hash`: the hash of a slash tx to be processed. + +**Returns**: + +a dictionary with the timestamp of the slashing and the `OperatorSlashed` events. + + + +#### get`_`operators`_`mapping + +```python +@classmethod +def get_operators_mapping(cls, ledger_api: LedgerApi, contract_address: str, + agent_instances: FrozenSet[str]) -> Dict[str, str] +``` + +Retrieve a mapping of the given agent instances to their operators. + +Please keep in mind that this method performs a call for each agent instance. + +**Arguments**: + +- `ledger_api`: the ledger api. +- `contract_address`: the contract address. +- `agent_instances`: the agent instances to be mapped. + +**Returns**: + +a mapping of the given agent instances to their operators. + diff --git a/docs/api/data/contracts/service_registry_token_utility/contract.md b/docs/api/data/contracts/service_registry_token_utility/contract.md new file mode 100644 index 0000000000..73b7e27ee3 --- /dev/null +++ b/docs/api/data/contracts/service_registry_token_utility/contract.md @@ -0,0 +1,115 @@ + + +# autonomy.data.contracts.service`_`registry`_`token`_`utility.contract + +This module contains the scaffold contract definition. + + + +## ServiceRegistryTokenUtilityContract Objects + +```python +class ServiceRegistryTokenUtilityContract(Contract) +``` + +The scaffold contract class for a smart contract. + + + +#### get`_`raw`_`transaction + +```python +@classmethod +def get_raw_transaction(cls, ledger_api: LedgerApi, contract_address: str, + **kwargs: Any) -> JSONLike +``` + +Handler method for the 'GET_RAW_TRANSACTION' requests. + +Implement this method in the sub class if you want +to handle the contract requests manually. + +**Arguments**: + +- `ledger_api`: the ledger apis. +- `contract_address`: the contract address. +- `kwargs`: the keyword arguments. + +**Returns**: + +the tx # noqa: DAR202 + + + +#### get`_`raw`_`message + +```python +@classmethod +def get_raw_message(cls, ledger_api: LedgerApi, contract_address: str, + **kwargs: Any) -> bytes +``` + +Handler method for the 'GET_RAW_MESSAGE' requests. + +Implement this method in the sub class if you want +to handle the contract requests manually. + +**Arguments**: + +- `ledger_api`: the ledger apis. +- `contract_address`: the contract address. +- `kwargs`: the keyword arguments. + +**Returns**: + +the tx # noqa: DAR202 + + + +#### get`_`state + +```python +@classmethod +def get_state(cls, ledger_api: LedgerApi, contract_address: str, + **kwargs: Any) -> JSONLike +``` + +Handler method for the 'GET_STATE' requests. + +Implement this method in the sub class if you want +to handle the contract requests manually. + +**Arguments**: + +- `ledger_api`: the ledger apis. +- `contract_address`: the contract address. +- `kwargs`: the keyword arguments. + +**Returns**: + +the tx # noqa: DAR202 + + + +#### is`_`token`_`secured`_`service + +```python +@classmethod +def is_token_secured_service(cls, ledger_api: LedgerApi, contract_address: str, + service_id: int) -> JSONLike +``` + +Check if a service is secured service. + + + +#### get`_`agent`_`bond + +```python +@classmethod +def get_agent_bond(cls, ledger_api: LedgerApi, contract_address: str, + service_id: int, agent_id: int) -> JSONLike +``` + +Check if a service is secured service. + diff --git a/docs/api/deploy/base.md b/docs/api/deploy/base.md index f2b8e26ec8..5451982068 100644 --- a/docs/api/deploy/base.md +++ b/docs/api/deploy/base.md @@ -4,6 +4,28 @@ Base deployments module. + + +#### ENV`_`VAR`_`AEA`_`PASSWORD + +nosec + + + +#### ENV`_`VAR`_`DEPENDENCIES + +nosec + + + +#### tm`_`write`_`to`_`log + +```python +def tm_write_to_log() -> bool +``` + +Check the environment variable to see if the user wants to write to log file or not. + ## NotValidKeysFile Objects @@ -31,33 +53,41 @@ Class to assist with generating deployments. ```python def __init__(service: Service, keys: Optional[List[Dict[str, str]]] = None, - private_keys_password: Optional[str] = None, agent_instances: Optional[List[str]] = None, apply_environment_variables: bool = False) -> None ``` Initialize the Base Deployment. - + -#### try`_`get`_`all`_`participants +#### get`_`abci`_`container`_`name ```python -def try_get_all_participants() -> Optional[List[str]] +def get_abci_container_name(index: int) -> str ``` -Try get all participants from the ABCI overrides +Format ABCI container name. - + -#### private`_`keys`_`password +#### get`_`tm`_`container`_`name ```python -@property -def private_keys_password() -> Optional[str] +def get_tm_container_name(index: int) -> str ``` -Service password for agent keys. +Format tendermint container name. + + + +#### try`_`get`_`all`_`participants + +```python +def try_get_all_participants() -> Optional[List[str]] +``` + +Try get all participants from the ABCI overrides @@ -102,7 +132,6 @@ def from_dir(cls, path: Path, keys_file: Optional[Path] = None, number_of_agents: Optional[int] = None, - private_keys_password: Optional[str] = None, agent_instances: Optional[List[str]] = None, apply_environment_variables: bool = False) -> "ServiceBuilder" ``` diff --git a/docs/api/deploy/build.md b/docs/api/deploy/build.md index 050d6cfc9b..711873ecad 100644 --- a/docs/api/deploy/build.md +++ b/docs/api/deploy/build.md @@ -14,7 +14,6 @@ def generate_deployment(type_of_deployment: str, service_path: Path, build_dir: Path, number_of_agents: Optional[int] = None, - private_keys_password: Optional[str] = None, dev_mode: bool = False, packages_dir: Optional[Path] = None, open_aea_dir: Optional[Path] = None, diff --git a/docs/api/deploy/generators/docker_compose/base.md b/docs/api/deploy/generators/docker_compose/base.md index 8da8a3aa91..7aeb5357ee 100644 --- a/docs/api/deploy/generators/docker_compose/base.md +++ b/docs/api/deploy/generators/docker_compose/base.md @@ -9,9 +9,15 @@ Docker-compose Deployment Generator. #### build`_`tendermint`_`node`_`config ```python -def build_tendermint_node_config(node_id: int, - dev_mode: bool = False, - log_level: str = INFO) -> str +def build_tendermint_node_config( + node_id: int, + container_name: str, + abci_node: str, + network_name: str, + network_address: str, + dev_mode: bool = False, + log_level: str = INFO, + tendermint_ports: Optional[Dict[int, int]] = None) -> str ``` Build tendermint node config for docker compose. @@ -22,9 +28,11 @@ Build tendermint node config for docker compose. ```python def build_agent_config(node_id: int, - number_of_agents: int, + container_name: str, agent_vars: Dict, runtime_image: str, + network_name: str, + network_address: str, dev_mode: bool = False, package_dir: Path = DEFAULT_PACKAGES_PATH, open_aea_dir: Path = DEFAULT_OPEN_AEA_DIR, @@ -34,6 +42,58 @@ def build_agent_config(node_id: int, Build agent config. + + +## Network Objects + +```python +class Network() +``` + +Class to represent network of the service. + + + +#### `__`init`__` + +```python +def __init__(name: str, base: ipaddress.IPv4Network = BASE_SUBNET) -> None +``` + +Initialize. + + + +#### next`_`subnet + +```python +@staticmethod +def next_subnet(subnet: ipaddress.IPv4Network) -> ipaddress.IPv4Network +``` + +Calculat next available subnet. + + + +#### build + +```python +def build() -> ipaddress.IPv4Network +``` + +Initialize network params. + + + +#### next`_`address + +```python +@property +def next_address() -> str +``` + +Returns the next IP address string. + ## DockerComposeGenerator Objects diff --git a/docs/api/deploy/image.md b/docs/api/deploy/image.md index 0667e1f256..d5a5cf2b05 100644 --- a/docs/api/deploy/image.md +++ b/docs/api/deploy/image.md @@ -4,6 +4,16 @@ Image building. + + +#### generate`_`dependency`_`flag`_`var + +```python +def generate_dependency_flag_var(dependencies: Tuple[Dependency, ...]) -> str +``` + +Generate dependency flag env var + ## ImageProfiles Objects @@ -23,7 +33,9 @@ def build_image(agent: PublicId, pull: bool = False, dev: bool = False, version: Optional[str] = None, - image_author: Optional[str] = None) -> None + image_author: Optional[str] = None, + extra_dependencies: Optional[Tuple[Dependency, ...]] = None, + dockerfile: Optional[Path] = None) -> None ``` Command to build images from for skaffold deployment. diff --git a/docs/api/plugins/aea_test_autonomy/base_test_classes/agents.md b/docs/api/plugins/aea_test_autonomy/base_test_classes/agents.md index 4ef4fa7b7b..eb2ba9361c 100644 --- a/docs/api/plugins/aea_test_autonomy/base_test_classes/agents.md +++ b/docs/api/plugins/aea_test_autonomy/base_test_classes/agents.md @@ -151,6 +151,42 @@ Test that an agent that is launched later can synchronize with the rest of the n responses that are forwarded again via the ABCI connection such that the Tendermint node can receive the responses + + +#### nb`_`nodes + +number of agents with tendermint nodes + + + +#### stop`_`string + +mandatory argument if n_terminal > 0 + + + +#### n`_`terminal + +number of agents to be restarted + + + +#### wait`_`to`_`kill + +delay the termination event + + + +#### restart`_`after + +how long to wait before restart + + + +#### wait`_`before`_`stop + +how long to check logs for `stop_string` + #### check diff --git a/docs/api/plugins/aea_test_autonomy/configurations.md b/docs/api/plugins/aea_test_autonomy/configurations.md index a254513f78..334bbde0dc 100644 --- a/docs/api/plugins/aea_test_autonomy/configurations.md +++ b/docs/api/plugins/aea_test_autonomy/configurations.md @@ -4,3 +4,21 @@ Test tools configuration. + + +#### CUR`_`PATH + +type: ignore + + + +#### ETHEREUM`_`ENCRYPTION`_`PASSWORD + +nosec + + + +#### ANY`_`ADDRESS + +nosec + diff --git a/docs/api/plugins/aea_test_autonomy/docker/registries.md b/docs/api/plugins/aea_test_autonomy/docker/registries.md index d86c4e84e4..294a8afa7b 100644 --- a/docs/api/plugins/aea_test_autonomy/docker/registries.md +++ b/docs/api/plugins/aea_test_autonomy/docker/registries.md @@ -4,6 +4,108 @@ Tendermint Docker image. + + +#### DEFAULT`_`ACCOUNT + +nosec + + + +#### COMPONENT`_`REGISTRY + +nosec + + + +#### AGENT`_`REGISTRY + +nosec + + + +#### REGISTRIES`_`MANAGER + +nosec + + + +#### GNOSIS`_`SAFE`_`MULTISIG + +nosec + + + +#### SERVICE`_`REGISTRY + +nosec + + + +#### SERVICE`_`REGISTRY`_`TOKEN`_`UTILITY + +nosec + + + +#### SERVICE`_`MANAGER`_`TOKEN + +nosec + + + +#### SERVICE`_`REGISTRY`_`L2 + +nosec + + + +#### SERVICE`_`MANAGER + +nosec + + + +#### OPERATOR`_`WHITELIST + +nosec + + + +#### ERC20`_`TOKEN + +nosec + + + +#### GNOSIS`_`SAFE`_`MASTER`_`COPY + +nosec + + + +#### GNOSIS`_`SAFE`_`PROXY`_`FACTORY + +nosec + + + +#### GNOSIS`_`SAFE`_`MULTISEND + +nosec + + + +#### SERVICE`_`MULTISIG`_`1 + +nosec + + + +#### SERVICE`_`MULTISIG`_`2 + +nosec + ## RegistriesDockerImage Objects diff --git a/docs/api/protocols/abci/custom_types.md b/docs/api/protocols/abci/custom_types.md index f560c6c657..e0b60c42c0 100644 --- a/docs/api/protocols/abci/custom_types.md +++ b/docs/api/protocols/abci/custom_types.md @@ -1537,6 +1537,42 @@ class ResultType(Enum) This class represents an instance of ResultType. + + +#### UNKNOWN + +Unknown result, abort all snapshot restoration + + + +#### ACCEPT + +Snapshot accepted, apply chunks + + + +#### ABORT + +Abort all snapshot restoration + + + +#### REJECT + +Reject this specific snapshot, try others + + + +#### REJECT`_`FORMAT + +Reject all snapshots of this format, try others + + + +#### REJECT`_`SENDER + +Reject all snapshots from the sender(s), try others + ## Result Objects diff --git a/docs/api/replay/agent.md b/docs/api/replay/agent.md index 8e163ec41d..1e80df4961 100644 --- a/docs/api/replay/agent.md +++ b/docs/api/replay/agent.md @@ -14,6 +14,12 @@ class AgentRunner() Agent runner. + + +#### process + +nosec + #### `__`init`__` diff --git a/docs/api/replay/tendermint.md b/docs/api/replay/tendermint.md index 196f92eb0e..d667e7d9b2 100644 --- a/docs/api/replay/tendermint.md +++ b/docs/api/replay/tendermint.md @@ -24,6 +24,12 @@ class TendermintRunner() Run tednermint using the dump. + + +#### process + +nosec + #### `__`init`__` diff --git a/docs/api/skills/abstract_round_abci/base.md b/docs/api/skills/abstract_round_abci/base.md index 3a34dfd9c1..53b3e30155 100644 --- a/docs/api/skills/abstract_round_abci/base.md +++ b/docs/api/skills/abstract_round_abci/base.md @@ -986,6 +986,28 @@ def nb_participants() -> int Get the number of participants. + + +#### slashing`_`config + +```python +@property +def slashing_config() -> str +``` + +Get the slashing configuration. + + + +#### slashing`_`config + +```python +@slashing_config.setter +def slashing_config(config: str) -> None +``` + +Set the slashing configuration. + #### update @@ -1166,6 +1188,7 @@ Optionally, round_id can be defined, although it is recommended to use the autog ```python def __init__( synchronized_data: BaseSynchronizedData, + context: SkillContext, previous_round_payload_class: Optional[Type[BaseTxPayload]] = None ) -> None ``` @@ -2065,6 +2088,138 @@ def __new__(mcs, name: str, bases: Tuple, namespace: Dict, Initialize the class. + + +## BackgroundAppType Objects + +```python +class BackgroundAppType(Enum) +``` + +The type of a background app. + +Please note that the values correspond to the priority in which the background apps should be processed +when updating rounds. + + + +#### correct`_`types + +```python +@staticmethod +def correct_types() -> Set[str] +``` + +Return the correct types only. + + + +## BackgroundAppConfig Objects + +```python +@dataclass(frozen=True) +class BackgroundAppConfig(Generic[EventType]) +``` + +Necessary configuration for a background app. + +For a deeper understanding of the various types of background apps and how the config influences +the generated background app's type, please refer to the `BackgroundApp` class. +The `specify_type` method provides further insight on the subject matter. + + + +## BackgroundApp Objects + +```python +class BackgroundApp(Generic[EventType]) +``` + +A background app. + + + +#### `__`init`__` + +```python +def __init__(config: BackgroundAppConfig) -> None +``` + +Initialize the BackgroundApp. + + + +#### `__`eq`__` + +```python +def __eq__(other: Any) -> bool +``` + +Custom equality comparing operator. + + + +#### `__`hash`__` + +```python +def __hash__() -> int +``` + +Custom hashing operator + + + +#### specify`_`type + +```python +def specify_type() -> BackgroundAppType +``` + +Specify the type of the background app. + + + +#### setup + +```python +def setup(initial_synchronized_data: BaseSynchronizedData, + context: SkillContext) -> None +``` + +Set up the background round. + + + +#### background`_`round + +```python +@property +def background_round() -> AbstractRound +``` + +Get the background round. + + + +#### process`_`transaction + +```python +def process_transaction(transaction: Transaction, dry: bool = False) -> bool +``` + +Process a transaction. + + + +## TransitionBackup Objects + +```python +@dataclass +class TransitionBackup() +``` + +Holds transition related information as a backup in case we want to transition back from a background app. + ## AbciApp Objects @@ -2082,7 +2237,8 @@ Concrete classes of this class implement the ABCI App. #### `__`init`__` ```python -def __init__(synchronized_data: BaseSynchronizedData, logger: logging.Logger) +def __init__(synchronized_data: BaseSynchronizedData, logger: logging.Logger, + context: SkillContext) ``` Initialize the AbciApp. @@ -2098,18 +2254,28 @@ def is_abstract(cls) -> bool Return if the abci app is abstract. - + -#### add`_`termination +#### add`_`background`_`app ```python @classmethod -def add_termination(cls, background_round_cls: AppState, - termination_event: EventType, - termination_abci_app: Type["AbciApp"]) -> Type["AbciApp"] +def add_background_app(cls, config: BackgroundAppConfig) -> Type["AbciApp"] ``` -Sets the termination related class variables. +Sets the background related class variables. + +For a deeper understanding of the various types of background apps and how the inputs of this method influence +the generated background app's type, please refer to the `BackgroundApp` class. +The `specify_type` method provides further insight on the subject matter. + +**Arguments**: + +- `config`: the background app's configuration. + +**Returns**: + +the `AbciApp` with the new background app contained in the `background_apps` set. @@ -2150,13 +2316,25 @@ Get all the events. ```python @classmethod -def get_all_round_classes(cls, - include_termination_rounds: bool = False - ) -> Set[AppState] +def get_all_round_classes( + cls, + bg_round_cls: Set[Type[AbstractRound]], + include_background_rounds: bool = False) -> Set[AppState] ``` Get all round classes. + + +#### bg`_`apps`_`prioritized + +```python +@property +def bg_apps_prioritized() -> Tuple[List[BackgroundApp], ...] +``` + +Get the background apps grouped and prioritized by their types. + #### last`_`timestamp @@ -2209,28 +2387,6 @@ def current_round() -> AbstractRound Get the current round. - - -#### background`_`round - -```python -@property -def background_round() -> AbstractRound -``` - -Get the background round. - - - -#### is`_`termination`_`set - -```python -@property -def is_termination_set() -> bool -``` - -Get whether termination is set. - #### current`_`round`_`id @@ -2309,31 +2465,24 @@ def check_transaction(transaction: Transaction) -> None Check a transaction. -The background round runs concurrently with other (normal) rounds. -First we check if the transaction is meant for the background round, -if not we forward to the current round object. - -**Arguments**: - -- `transaction`: the transaction. - #### process`_`transaction ```python -def process_transaction(transaction: Transaction) -> None +def process_transaction(transaction: Transaction, dry: bool = False) -> None ``` Process a transaction. -The background round runs concurrently with other (normal) rounds. -First we check if the transaction is meant for the background round, -if not we forward to the current round object. +The background rounds run concurrently with other (normal) rounds. +First we check if the transaction is meant for a background round, +if not we forward it to the current round object. **Arguments**: - `transaction`: the transaction. +- `dry`: whether the transaction should only be checked and not processed. @@ -2381,6 +2530,257 @@ def cleanup_current_histories(cleanup_history_depth_current: int) -> None Reset the parameter histories for the current entry (period), keeping only the latest values for each parameter. + + +## OffenseType Objects + +```python +class OffenseType(Enum) +``` + +The types of offenses. + +The values of the enum represent the seriousness of the offence. +Offense types with values >1000 are considered serious. +See also `is_light_offence` and `is_serious_offence` functions. + + + +#### is`_`light`_`offence + +```python +def is_light_offence(offence_type: OffenseType) -> bool +``` + +Check if an offence type is light. + + + +#### is`_`serious`_`offence + +```python +def is_serious_offence(offence_type: OffenseType) -> bool +``` + +Check if an offence type is serious. + + + +#### light`_`offences + +```python +def light_offences() -> Iterator[OffenseType] +``` + +Get the light offences. + + + +#### serious`_`offences + +```python +def serious_offences() -> Iterator[OffenseType] +``` + +Get the serious offences. + + + +## AvailabilityWindow Objects + +```python +class AvailabilityWindow() +``` + +A cyclic array with a maximum length that holds boolean values. + +When an element is added to the array and the maximum length has been reached, +the oldest element is removed. Two attributes `num_positive` and `num_negative` +reflect the number of positive and negative elements in the AvailabilityWindow, +they are updated every time a new element is added. + + + +#### `__`init`__` + +```python +def __init__(max_length: int) -> None +``` + +Initializes the `AvailabilityWindow` instance. + +**Arguments**: + +- `max_length`: the maximum length of the cyclic array. + + + +#### `__`eq`__` + +```python +def __eq__(other: Any) -> bool +``` + +Compare `AvailabilityWindow` objects. + + + +#### has`_`bad`_`availability`_`rate + +```python +def has_bad_availability_rate(threshold: float = 0.95) -> bool +``` + +Whether the agent on which the window belongs to has a bad availability rate or not. + + + +#### add + +```python +def add(value: bool) -> None +``` + +Adds a new boolean value to the cyclic array. + +If the maximum length has been reached, the oldest element is removed. + +**Arguments**: + +- `value`: The boolean value to add to the cyclic array. + + + +#### to`_`dict + +```python +def to_dict() -> Dict[str, int] +``` + +Returns a dictionary representation of the `AvailabilityWindow` instance. + + + +#### from`_`dict + +```python +@classmethod +def from_dict(cls, data: Dict[str, int]) -> "AvailabilityWindow" +``` + +Initializes an `AvailabilityWindow` instance from a dictionary. + + + +## OffenceStatus Objects + +```python +@dataclass +class OffenceStatus() +``` + +A class that holds information about offence status for an agent. + + + +#### slash`_`amount + +```python +def slash_amount(light_unit_amount: int, serious_unit_amount: int) -> int +``` + +Get the slash amount of the current status. + + + +## OffenseStatusEncoder Objects + +```python +class OffenseStatusEncoder(json.JSONEncoder) +``` + +A custom JSON encoder for the offence status dictionary. + + + +#### default + +```python +def default(o: Any) -> Any +``` + +The default JSON encoder. + + + +## OffenseStatusDecoder Objects + +```python +class OffenseStatusDecoder(json.JSONDecoder) +``` + +A custom JSON decoder for the offence status dictionary. + + + +#### `__`init`__` + +```python +def __init__(*args: Any, **kwargs: Any) -> None +``` + +Initialize the custom JSON decoder. + + + +#### hook + +```python +@staticmethod +def hook( + data: Dict[str, Any] +) -> Union[AvailabilityWindow, OffenceStatus, Dict[str, OffenceStatus]] +``` + +Perform the custom decoding. + + + +## PendingOffense Objects + +```python +@dataclass(frozen=True, eq=True) +class PendingOffense() +``` + +A dataclass to represent offences that need to be addressed. + + + +#### `__`post`_`init`__` + +```python +def __post_init__() -> None +``` + +Post initialization for offence type conversion in case it is given as an `int`. + + + +## SlashingNotConfiguredError Objects + +```python +class SlashingNotConfiguredError(Exception) +``` + +Custom exception raised when slashing configuration is requested but is not available. + + + +#### DEFAULT`_`PENDING`_`OFFENCE`_`TTL + +1 hour + ## RoundSequence Objects @@ -2402,11 +2802,127 @@ It also schedules the next round (if any) whenever a round terminates. #### `__`init`__` ```python -def __init__(abci_app_cls: Type[AbciApp]) +def __init__(context: SkillContext, abci_app_cls: Type[AbciApp]) ``` Initialize the round. + + +#### enable`_`slashing + +```python +def enable_slashing() -> None +``` + +Enable slashing. + + + +#### validator`_`to`_`agent + +```python +@property +def validator_to_agent() -> Dict[str, str] +``` + +Get the mapping of the validators' addresses to their agent addresses. + + + +#### validator`_`to`_`agent + +```python +@validator_to_agent.setter +def validator_to_agent(validator_to_agent: Dict[str, str]) -> None +``` + +Set the mapping of the validators' addresses to their agent addresses. + + + +#### offence`_`status + +```python +@property +def offence_status() -> Dict[str, OffenceStatus] +``` + +Get the mapping of the agents' addresses to their offence status. + + + +#### offence`_`status + +```python +@offence_status.setter +def offence_status(offence_status: Dict[str, OffenceStatus]) -> None +``` + +Set the mapping of the agents' addresses to their offence status. + + + +#### add`_`pending`_`offence + +```python +def add_pending_offence(pending_offence: PendingOffense) -> None +``` + +Add a pending offence to the set of pending offences. + +Pending offences are offences that have been detected, but not yet agreed upon by the consensus. +A pending offence is removed from the set of pending offences and added to the OffenceStatus of a validator +when the majority of the agents agree on it. + +**Arguments**: + +- `pending_offence`: the pending offence to add + +**Returns**: + +None + + + +#### sync`_`db`_`and`_`slashing + +```python +def sync_db_and_slashing(serialized_db_state: str) -> None +``` + +Sync the database and the slashing configuration. + + + +#### serialized`_`offence`_`status + +```python +def serialized_offence_status() -> str +``` + +Serialize the offence status. + + + +#### store`_`offence`_`status + +```python +def store_offence_status() -> None +``` + +Store the serialized offence status. + + + +#### get`_`agent`_`address + +```python +def get_agent_address(validator: Validator) -> str +``` + +Get corresponding agent address from a `Validator` instance. + #### setup @@ -2532,17 +3048,6 @@ def current_round() -> AbstractRound Get current round. - - -#### background`_`round - -```python -@property -def background_round() -> AbstractRound -``` - -Get the background round. - #### current`_`round`_`id @@ -2694,6 +3199,16 @@ def block_stall_deadline_expired() -> bool Get if the deadline for not having received any begin block requests from the Tendermint node has expired. + + +#### set`_`block`_`stall`_`deadline + +```python +def set_block_stall_deadline() -> None +``` + +Use the local time of the agent and a predefined tolerance, to specify the expiration of the deadline. + #### init`_`chain @@ -2709,7 +3224,8 @@ Init chain. #### begin`_`block ```python -def begin_block(header: Header) -> None +def begin_block(header: Header, evidences: Evidences, + last_commit_info: LastCommitInfo) -> None ``` Begin block. @@ -2779,13 +3295,72 @@ def reset_state(restart_from_round: str, serialized_db_state: Optional[str] = None) -> None ``` -This method resets the state of RoundSequence to the begging of the period. +This method resets the state of RoundSequence to the beginning of the period. -Note: This is intended to be used only for agent <-> tendermint communication recovery only! +Note: This is intended to be used for agent <-> tendermint communication recovery only! **Arguments**: -- `restart_from_round`: from which round to restart the abci. This round should be the first round in the last period. +- `restart_from_round`: from which round to restart the abci. +This round should be the first round in the last period. - `round_count`: the round count at the beginning of the period -1. -- `serialized_db_state`: the state of the database at the beginning of the period. If provided, the database will be reset to this state. +- `serialized_db_state`: the state of the database at the beginning of the period. +If provided, the database will be reset to this state. + + + +## PendingOffencesPayload Objects + +```python +@dataclass(frozen=True) +class PendingOffencesPayload(BaseTxPayload) +``` + +Represent a transaction payload for pending offences. + + + +## PendingOffencesRound Objects + +```python +class PendingOffencesRound(CollectSameUntilThresholdRound) +``` + +Defines the pending offences background round, which runs concurrently with other rounds to sync the offences. + + + +#### `__`init`__` + +```python +def __init__(*args: Any, **kwargs: Any) -> None +``` + +Initialize the `PendingOffencesRound`. + + + +#### offence`_`status + +```python +@property +def offence_status() -> Dict[str, OffenceStatus] +``` + +Get the offence status from the round sequence. + + + +#### end`_`block + +```python +def end_block() -> None +``` + +Process the end of the block for the pending offences background round. + +It is important to note that this is a non-standard type of round, meaning it does not emit any events. +Instead, it continuously runs in the background. +The objective of this round is to consistently monitor the received pending offences +and achieve a consensus among the agents. diff --git a/docs/api/skills/abstract_round_abci/behaviour_utils.md b/docs/api/skills/abstract_round_abci/behaviour_utils.md index e69de29bb2..62ebb3f72e 100644 --- a/docs/api/skills/abstract_round_abci/behaviour_utils.md +++ b/docs/api/skills/abstract_round_abci/behaviour_utils.md @@ -0,0 +1,1072 @@ + + +# packages.valory.skills.abstract`_`round`_`abci.behaviour`_`utils + +This module contains helper classes for behaviours. + + + +#### TM`_`REQ`_`TIMEOUT + +5 seconds + + + +## SendException Objects + +```python +class SendException(Exception) +``` + +Exception raised if the 'try_send' to an AsyncBehaviour failed. + + + +## TimeoutException Objects + +```python +class TimeoutException(Exception) +``` + +Exception raised when a timeout during AsyncBehaviour occurs. + + + +## BaseBehaviourInternalError Objects + +```python +class BaseBehaviourInternalError(Exception) +``` + +Internal error due to a bad implementation of the BaseBehaviour. + + + +#### `__`init`__` + +```python +def __init__(message: str, *args: Any) -> None +``` + +Initialize the error object. + + + +## AsyncBehaviour Objects + +```python +class AsyncBehaviour(ABC) +``` + +MixIn behaviour class that support limited asynchronous programming. + +An AsyncBehaviour can be in three states: +- READY: no suspended 'async_act' execution; +- RUNNING: 'act' called, and waiting for a message +- WAITING_TICK: 'act' called, and waiting for the next 'act' call + + + +## AsyncState Objects + +```python +class AsyncState(Enum) +``` + +Enumeration of AsyncBehaviour states. + + + +#### `__`init`__` + +```python +def __init__() -> None +``` + +Initialize the async behaviour. + + + +#### async`_`act + +```python +@abstractmethod +def async_act() -> Generator +``` + +Do the act, supporting asynchronous execution. + + + +#### async`_`act`_`wrapper + +```python +@abstractmethod +def async_act_wrapper() -> Generator +``` + +Do the act, supporting asynchronous execution. + + + +#### state + +```python +@property +def state() -> AsyncState +``` + +Get the 'async state'. + + + +#### is`_`notified + +```python +@property +def is_notified() -> bool +``` + +Returns whether the behaviour has been notified about the arrival of a message. + + + +#### received`_`message + +```python +@property +def received_message() -> Any +``` + +Returns the message the behaviour has received. "__message" should be None if not availble or already consumed. + + + +#### is`_`stopped + +```python +@property +def is_stopped() -> bool +``` + +Check whether the behaviour has stopped. + + + +#### try`_`send + +```python +def try_send(message: Any) -> None +``` + +Try to send a message to a waiting behaviour. + +It will be sent only if the behaviour is actually waiting for a message, +and it was not already notified. + +**Arguments**: + +- `message`: a Python object. + +**Raises**: + +- `None`: SendException if the behaviour was not waiting for a message, +or if it was already notified. + + + +#### wait`_`for`_`condition + +```python +@classmethod +def wait_for_condition( + cls, + condition: Callable[[], bool], + timeout: Optional[float] = None) -> Generator[None, None, None] +``` + +Wait for a condition to happen. + +This is a local method that does not depend on the global clock, +so the usage of datetime.now() is acceptable here. + +**Arguments**: + +- `condition`: the condition to wait for +- `timeout`: the maximum amount of time to wait + +**Returns**: + +None + + + +#### sleep + +```python +def sleep(seconds: float) -> Any +``` + +Delay execution for a given number of seconds. + +The argument may be a floating point number for subsecond precision. +This is a local method that does not depend on the global clock, so the +usage of datetime.now() is acceptable here. + +**Arguments**: + +- `seconds`: the seconds + +**Returns**: + +None + + + +#### wait`_`for`_`message + +```python +def wait_for_message(condition: Callable = lambda message: True, + timeout: Optional[float] = None) -> Any +``` + +Wait for message. + +Care must be taken. This method does not handle concurrent requests. +Use directly after a request is being sent. +This is a local method that does not depend on the global clock, +so the usage of datetime.now() is acceptable here. + +**Arguments**: + +- `condition`: a callable +- `timeout`: max time to wait (in seconds) + +**Returns**: + +a message + + + +#### setup + +```python +def setup() -> None +``` + +Setup behaviour. + + + +#### act + +```python +def act() -> None +``` + +Do the act. + + + +#### stop + +```python +def stop() -> None +``` + +Stop the execution of the behaviour. + + + +## IPFSBehaviour Objects + +```python +class IPFSBehaviour(SimpleBehaviour, ABC) +``` + +Behaviour for interactions with IPFS. + + + +#### `__`init`__` + +```python +def __init__(**kwargs: Any) +``` + +Initialize an `IPFSBehaviour`. + + + +## CleanUpBehaviour Objects + +```python +class CleanUpBehaviour(SimpleBehaviour, ABC) +``` + +Class for clean-up related functionality of behaviours. + + + +#### `__`init`__` + +```python +def __init__(**kwargs: Any) +``` + +Initialize a base behaviour. + + + +#### clean`_`up + +```python +def clean_up() -> None +``` + +Clean up the resources due to a 'stop' event. + +It can be optionally implemented by the concrete classes. + + + +#### handle`_`late`_`messages + +```python +def handle_late_messages(behaviour_id: str, message: Message) -> None +``` + +Handle late arriving messages. + +Runs from another behaviour, even if the behaviour implementing the method has been exited. +It can be optionally implemented by the concrete classes. + +**Arguments**: + +- `behaviour_id`: the id of the behaviour in which the message belongs to. +- `message`: the late arriving message to handle. + + + +## RPCResponseStatus Objects + +```python +class RPCResponseStatus(Enum) +``` + +A custom status of an RPC response. + + + +## `_`MetaBaseBehaviour Objects + +```python +class _MetaBaseBehaviour(ABCMeta) +``` + +A metaclass that validates BaseBehaviour's attributes. + + + +#### `__`new`__` + +```python +def __new__(mcs, name: str, bases: Tuple, namespace: Dict, + **kwargs: Any) -> Type +``` + +Initialize the class. + + + +## BaseBehaviour Objects + +```python +class BaseBehaviour(AsyncBehaviour, + IPFSBehaviour, + CleanUpBehaviour, + ABC, + metaclass=_MetaBaseBehaviour) +``` + +This class represents the base class for FSM behaviours + +A behaviour is a state of the FSM App execution. It usually involves +interactions between participants in the FSM App, +although this is not enforced at this level of abstraction. + +Concrete classes must set: +- matching_round: the round class matching the behaviour; + +Optionally, behaviour_id can be defined, although it is recommended to use the autogenerated id. + + + +#### `__`init`__` + +```python +def __init__(**kwargs: Any) +``` + +Initialize a base behaviour. + + + +#### auto`_`behaviour`_`id + +```python +@classmethod +def auto_behaviour_id(cls) -> str +``` + +Get behaviour id automatically. + +This method returns the auto generated id from the class name if the +class variable behaviour_id is not set on the child class. +Otherwise, it returns the class variable behaviour_id. + + + +#### behaviour`_`id + +```python +@property +def behaviour_id() -> str +``` + +Get behaviour id. + + + +#### params + +```python +@property +def params() -> BaseParams +``` + +Return the params. + + + +#### shared`_`state + +```python +@property +def shared_state() -> SharedState +``` + +Return the round sequence. + + + +#### round`_`sequence + +```python +@property +def round_sequence() -> RoundSequence +``` + +Return the round sequence. + + + +#### synchronized`_`data + +```python +@property +def synchronized_data() -> BaseSynchronizedData +``` + +Return the synchronized data. + + + +#### tm`_`communication`_`unhealthy + +```python +@property +def tm_communication_unhealthy() -> bool +``` + +Return if the Tendermint communication is not healthy anymore. + + + +#### check`_`in`_`round + +```python +def check_in_round(round_id: str) -> bool +``` + +Check that we entered a specific round. + + + +#### check`_`in`_`last`_`round + +```python +def check_in_last_round(round_id: str) -> bool +``` + +Check that we entered a specific round. + + + +#### check`_`not`_`in`_`round + +```python +def check_not_in_round(round_id: str) -> bool +``` + +Check that we are not in a specific round. + + + +#### check`_`not`_`in`_`last`_`round + +```python +def check_not_in_last_round(round_id: str) -> bool +``` + +Check that we are not in a specific round. + + + +#### check`_`round`_`has`_`finished + +```python +def check_round_has_finished(round_id: str) -> bool +``` + +Check that the round has finished. + + + +#### check`_`round`_`height`_`has`_`changed + +```python +def check_round_height_has_changed(round_height: int) -> bool +``` + +Check that the round height has changed. + + + +#### is`_`round`_`ended + +```python +def is_round_ended(round_id: str) -> Callable[[], bool] +``` + +Get a callable to check whether the current round has ended. + + + +#### wait`_`until`_`round`_`end + +```python +def wait_until_round_end( + timeout: Optional[float] = None) -> Generator[None, None, None] +``` + +Wait until the ABCI application exits from a round. + +**Arguments**: + +- `timeout`: the timeout for the wait + +**Returns**: + +None + + + +#### wait`_`from`_`last`_`timestamp + +```python +def wait_from_last_timestamp(seconds: float) -> Any +``` + +Delay execution for a given number of seconds from the last timestamp. + +The argument may be a floating point number for subsecond precision. +This is a local method that does not depend on the global clock, +so the usage of datetime.now() is acceptable here. + +**Arguments**: + +- `seconds`: the seconds + +**Returns**: + +None + + + +#### is`_`done + +```python +def is_done() -> bool +``` + +Check whether the behaviour is done. + + + +#### set`_`done + +```python +def set_done() -> None +``` + +Set the behaviour to done. + + + +#### send`_`a2a`_`transaction + +```python +def send_a2a_transaction(payload: BaseTxPayload, + resetting: bool = False) -> Generator +``` + +Send transaction and wait for the response, and repeat until not successful. + +:param: payload: the payload to send +:param: resetting: flag indicating if we are resetting Tendermint nodes in this round. +:yield: the responses + + + + +#### async`_`act`_`wrapper + +```python +def async_act_wrapper() -> Generator +``` + +Do the act, supporting asynchronous execution. + + + +#### num`_`active`_`peers + +```python +def num_active_peers( + timeout: Optional[float] = None +) -> Generator[None, None, Optional[int]] +``` + +Returns the number of active peers in the network. + + + +#### get`_`callback`_`request + +```python +def get_callback_request() -> Callable[[Message, "BaseBehaviour"], None] +``` + +Wrapper for callback request which depends on whether the message has not been handled on time. + +**Returns**: + +the request callback. + + + +#### get`_`http`_`response + +```python +def get_http_response( + method: str, + url: str, + content: Optional[bytes] = None, + headers: Optional[Dict[str, str]] = None, + parameters: Optional[Dict[str, str]] = None +) -> Generator[None, None, HttpMessage] +``` + +Send an http request message from the skill context. + +This method is skill-specific, and therefore +should not be used elsewhere. + +Happy-path full flow of the messages. + +_do_request: + AbstractRoundAbci skill -> (HttpMessage | REQUEST) -> Http client connection + Http client connection -> (HttpMessage | RESPONSE) -> AbstractRoundAbci skill + +**Arguments**: + +- `method`: the http request method (i.e. 'GET' or 'POST'). +- `url`: the url to send the message to. +- `content`: the payload. +- `headers`: headers to be included. +- `parameters`: url query parameters. + +**Returns**: + +HttpMessage object + + + +#### get`_`signature + +```python +def get_signature( + message: bytes, + is_deprecated_mode: bool = False) -> Generator[None, None, str] +``` + +Get signature for message. + +Happy-path full flow of the messages. + +_send_signing_request: + AbstractRoundAbci skill -> (SigningMessage | SIGN_MESSAGE) -> DecisionMaker + DecisionMaker -> (SigningMessage | SIGNED_MESSAGE) -> AbstractRoundAbci skill + +**Arguments**: + +- `message`: message bytes +- `is_deprecated_mode`: is deprecated mode flag + +**Returns**: + +SigningMessage object + + + +#### send`_`raw`_`transaction + +```python +def send_raw_transaction( + transaction: RawTransaction, + use_flashbots: bool = False, + target_block_numbers: Optional[List[int]] = None, + raise_on_failed_simulation: bool = False, + chain_id: Optional[str] = None +) -> Generator[ + None, + Union[None, SigningMessage, LedgerApiMessage], + Tuple[Optional[str], RPCResponseStatus], +] +``` + +Send raw transactions to the ledger for mining. + +Happy-path full flow of the messages. + +_send_transaction_signing_request: + AbstractRoundAbci skill -> (SigningMessage | SIGN_TRANSACTION) -> DecisionMaker + DecisionMaker -> (SigningMessage | SIGNED_TRANSACTION) -> AbstractRoundAbci skill + +_send_transaction_request: + AbstractRoundAbci skill -> (LedgerApiMessage | SEND_SIGNED_TRANSACTION) -> Ledger connection + Ledger connection -> (LedgerApiMessage | TRANSACTION_DIGEST) -> AbstractRoundAbci skill + +**Arguments**: + +- `transaction`: transaction data +- `use_flashbots`: whether to use flashbots for the transaction or not +- `target_block_numbers`: the target block numbers in case we are using flashbots +- `raise_on_failed_simulation`: whether to raise an exception if the transaction fails the simulation or not +- `chain_id`: the chain name to use for the ledger call + +**Returns**: + +SigningMessage object + + + +#### get`_`transaction`_`receipt + +```python +def get_transaction_receipt( + tx_digest: str, + retry_timeout: Optional[int] = None, + retry_attempts: Optional[int] = None +) -> Generator[None, None, Optional[Dict]] +``` + +Get transaction receipt. + +Happy-path full flow of the messages. + +_send_transaction_receipt_request: + AbstractRoundAbci skill -> (LedgerApiMessage | GET_TRANSACTION_RECEIPT) -> Ledger connection + Ledger connection -> (LedgerApiMessage | TRANSACTION_RECEIPT) -> AbstractRoundAbci skill + +**Arguments**: + +- `tx_digest`: transaction digest received from raw transaction. +- `retry_timeout`: retry timeout. +- `retry_attempts`: number of retry attempts allowed. + +**Returns**: + +LedgerApiMessage object + + + +#### get`_`ledger`_`api`_`response + +```python +def get_ledger_api_response( + performative: LedgerApiMessage.Performative, ledger_callable: str, + **kwargs: Any) -> Generator[None, None, LedgerApiMessage] +``` + +Request data from ledger api + +Happy-path full flow of the messages. + +AbstractRoundAbci skill -> (LedgerApiMessage | LedgerApiMessage.Performative) -> Ledger connection +Ledger connection -> (LedgerApiMessage | LedgerApiMessage.Performative) -> AbstractRoundAbci skill + +**Arguments**: + +- `performative`: the message performative +- `ledger_callable`: the callable to call on the contract +- `kwargs`: keyword argument for the contract api request + +**Returns**: + +the contract api response + + + +#### get`_`contract`_`api`_`response + +```python +def get_contract_api_response( + performative: ContractApiMessage.Performative, + contract_address: Optional[str], contract_id: str, + contract_callable: str, + **kwargs: Any) -> Generator[None, None, ContractApiMessage] +``` + +Request contract safe transaction hash + +Happy-path full flow of the messages. + +AbstractRoundAbci skill -> (ContractApiMessage | ContractApiMessage.Performative) -> Ledger connection (contract dispatcher) +Ledger connection (contract dispatcher) -> (ContractApiMessage | ContractApiMessage.Performative) -> AbstractRoundAbci skill + +**Arguments**: + +- `performative`: the message performative +- `contract_address`: the contract address +- `contract_id`: the contract id +- `contract_callable`: the callable to call on the contract +- `kwargs`: keyword argument for the contract api request + +**Returns**: + +the contract api response + + + +#### request`_`recovery`_`params + +```python +def request_recovery_params() -> Generator[None, None, bool] +``` + +Request the Tendermint recovery parameters from the other agents via the ACN. + + + +#### hard`_`reset`_`sleep + +```python +@property +def hard_reset_sleep() -> float +``` + +Amount of time to sleep before and after performing a hard reset. + +We sleep for half the reset pause duration as there are no immediate transactions on either side of the reset. + +**Returns**: + +the amount of time to sleep in seconds + + + +#### reset`_`tendermint`_`with`_`wait + +```python +def reset_tendermint_with_wait( + on_startup: bool = False, + is_recovery: bool = False) -> Generator[None, None, bool] +``` + +Performs a hard reset (unsafe-reset-all) on the tendermint node. + +**Arguments**: + +- `on_startup`: whether we are resetting on the start of the agent. +- `is_recovery`: whether the reset is being performed to recover the agent <-> tm communication. + +**Returns**: + +None + + + +#### send`_`to`_`ipfs + +```python +def send_to_ipfs(filename: str, + obj: SupportedObjectType, + multiple: bool = False, + filetype: Optional[SupportedFiletype] = None, + custom_storer: Optional[CustomStorerType] = None, + timeout: Optional[float] = None, + **kwargs: Any) -> Generator[None, None, Optional[str]] +``` + +Store an object on IPFS. + +**Arguments**: + +- `filename`: the file name to store obj in. If "multiple" is True, filename will be the name of the dir. +- `obj`: the object(s) to serialize and store in IPFS as "filename". +- `multiple`: whether obj should be stored as multiple files, i.e. directory. +- `filetype`: the file type of the object being downloaded. +- `custom_storer`: a custom serializer for "obj". +- `timeout`: timeout for the request. + +**Returns**: + +the downloaded object, corresponding to ipfs_hash. + + + +#### get`_`from`_`ipfs + +```python +def get_from_ipfs( + ipfs_hash: str, + filetype: Optional[SupportedFiletype] = None, + custom_loader: CustomLoaderType = None, + timeout: Optional[float] = None +) -> Generator[None, None, Optional[SupportedObjectType]] +``` + +Gets an object from IPFS. + +**Arguments**: + +- `ipfs_hash`: the ipfs hash of the file/dir to download. +- `filetype`: the file type of the object being downloaded. +- `custom_loader`: a custom deserializer for the object received from IPFS. +- `timeout`: timeout for the request. + +**Returns**: + +the downloaded object, corresponding to ipfs_hash. + + + +## TmManager Objects + +```python +class TmManager(BaseBehaviour) +``` + +Util class to be used for managing the tendermint node. + + + +#### async`_`act + +```python +def async_act() -> Generator +``` + +The behaviour act. + + + +#### is`_`acting + +```python +@property +def is_acting() -> bool +``` + +This method returns whether there is an active fix being applied. + + + +#### hard`_`reset`_`sleep + +```python +@property +def hard_reset_sleep() -> float +``` + +Amount of time to sleep before and after performing a hard reset. + +We don't need to wait for half the reset pause duration, like in normal cases where we perform a hard reset. + +**Returns**: + +the amount of time to sleep in seconds + + + +#### get`_`callback`_`request + +```python +def get_callback_request() -> Callable[[Message, "BaseBehaviour"], None] +``` + +Wrapper for callback_request(), overridden to remove checks not applicable to TmManager. + + + +#### try`_`fix + +```python +def try_fix() -> None +``` + +This method tries to fix an unhealthy tendermint node. + + + +## DegenerateBehaviour Objects + +```python +class DegenerateBehaviour(BaseBehaviour, ABC) +``` + +An abstract matching behaviour for final and degenerate rounds. + + + +#### async`_`act + +```python +def async_act() -> Generator +``` + +Exit the agent with error when a degenerate round is reached. + + + +#### make`_`degenerate`_`behaviour + +```python +def make_degenerate_behaviour( + round_cls: Type[AbstractRound]) -> Type[DegenerateBehaviour] +``` + +Make a degenerate behaviour class. + diff --git a/docs/api/skills/abstract_round_abci/behaviours.md b/docs/api/skills/abstract_round_abci/behaviours.md index e0eb374c7c..699d548fae 100644 --- a/docs/api/skills/abstract_round_abci/behaviours.md +++ b/docs/api/skills/abstract_round_abci/behaviours.md @@ -25,19 +25,85 @@ def __new__(mcs, name: str, bases: Tuple, namespace: Dict, Initialize the class. + + +## PendingOffencesBehaviour Objects + +```python +class PendingOffencesBehaviour(BaseBehaviour) +``` + +A behaviour responsible for checking whether there are any pending offences. + + + +#### round`_`sequence + +```python +@property +def round_sequence() -> RoundSequence +``` + +Get the round sequence from the shared state. + + + +#### pending`_`offences + +```python +@property +def pending_offences() -> Set[PendingOffense] +``` + +Get the pending offences from the round sequence. + + + +#### has`_`pending`_`offences + +```python +def has_pending_offences() -> bool +``` + +Check if there are any pending offences. + + + +#### async`_`act + +```python +def async_act() -> Generator +``` + +Checks the pending offences. + +This behaviour simply checks if the set of pending offences is not empty. +When it’s not empty, it pops the offence from the set, and sends it to the rest of the agents via a payload + +**Returns**: + +None + ## AbstractRoundBehaviour Objects ```python -class AbstractRoundBehaviour(Behaviour, - ABC, - Generic[EventType], - metaclass=_MetaRoundBehaviour) +class AbstractRoundBehaviour( # pylint: disable=too-many-instance-attributes + Behaviour, + ABC, + Generic[EventType], + metaclass=_MetaRoundBehaviour) ``` This behaviour implements an abstract round behaviour. + + +#### background`_`behaviours`_`cls + +type: ignore + #### `__`init`__` @@ -58,17 +124,6 @@ def instantiate_behaviour_cls(behaviour_cls: BehaviourType) -> BaseBehaviour Instantiate the behaviours class. - - -#### is`_`background`_`behaviour`_`set - -```python -@property -def is_background_behaviour_set() -> bool -``` - -Returns whether the background behaviour is set. - #### setup diff --git a/docs/api/skills/abstract_round_abci/common.md b/docs/api/skills/abstract_round_abci/common.md index e69de29bb2..955f98c96a 100644 --- a/docs/api/skills/abstract_round_abci/common.md +++ b/docs/api/skills/abstract_round_abci/common.md @@ -0,0 +1,108 @@ + + +# packages.valory.skills.abstract`_`round`_`abci.common + +This module contains the behaviours, round and payloads for the 'abstract_round_abci' skill. + + + +#### random`_`selection + +```python +def random_selection(elements: List[Any], randomness: float) -> str +``` + +Select a random element from a list. + +:param: elements: a list of elements to choose among +:param: randomness: a random number in the [0,1) interval +:return: a randomly chosen element + + + + +## RandomnessBehaviour Objects + +```python +class RandomnessBehaviour(BaseBehaviour, ABC) +``` + +Check whether Tendermint nodes are running. + + + +#### failsafe`_`randomness + +```python +def failsafe_randomness() -> Generator[None, None, RandomnessObservation] +``` + +This methods provides a failsafe for randomness retrieval. + +**Returns**: + +derived randomness + + + +#### get`_`randomness`_`from`_`api + +```python +def get_randomness_from_api() -> Generator[None, None, RandomnessObservation] +``` + +Retrieve randomness from given api specs. + + + +#### async`_`act + +```python +def async_act() -> Generator +``` + +Retrieve randomness from API. + +Steps: +- Do a http request to the API. +- Retry until receiving valid values for randomness or retries exceed. +- If retrieved values are valid continue else generate randomness from chain. + + + +#### clean`_`up + +```python +def clean_up() -> None +``` + +Clean up the resources due to a 'stop' event. + +It can be optionally implemented by the concrete classes. + + + +## SelectKeeperBehaviour Objects + +```python +class SelectKeeperBehaviour(BaseBehaviour, ABC) +``` + +Select the keeper agent. + + + +#### async`_`act + +```python +def async_act() -> Generator +``` + +Do the action. + +Steps: +- Select a keeper randomly. +- Send the transaction with the keeper and wait for it to be mined. +- Wait until ABCI application transitions to the next round. +- Go to the next behaviour state (set done event). + diff --git a/docs/api/skills/abstract_round_abci/handlers.md b/docs/api/skills/abstract_round_abci/handlers.md index 1051b43c1e..fa78319f1f 100644 --- a/docs/api/skills/abstract_round_abci/handlers.md +++ b/docs/api/skills/abstract_round_abci/handlers.md @@ -96,6 +96,17 @@ def check_tx(message: AbciMessage, dialogue: AbciDialogue) -> AbciMessage Handle the 'check_tx' request. + + +#### settle`_`pending`_`offence + +```python +def settle_pending_offence(accused_agent_address: Optional[str], + invalid: bool) -> None +``` + +Add an invalid pending offence or a no-offence for the given accused agent address, if possible. + #### deliver`_`tx diff --git a/docs/api/skills/abstract_round_abci/models.md b/docs/api/skills/abstract_round_abci/models.md index 233b22fce7..17f6e91d8d 100644 --- a/docs/api/skills/abstract_round_abci/models.md +++ b/docs/api/skills/abstract_round_abci/models.md @@ -2,7 +2,7 @@ # packages.valory.skills.abstract`_`round`_`abci.models -This module contains the shared state for the price estimation ABCI application. +This module contains the core models for all the ABCI apps. @@ -264,6 +264,26 @@ def __init__(*args: Any, skill_context: SkillContext, **kwargs: Any) -> None Initialize the state. + + +#### setup`_`slashing + +```python +def setup_slashing(validator_to_agent: Dict[str, str]) -> None +``` + +Initialize the structures required for slashing. + + + +#### get`_`validator`_`address + +```python +def get_validator_address(agent_address: str) -> str +``` + +Get the validator address of an agent. + #### acn`_`container diff --git a/docs/api/skills/abstract_round_abci/test_tools/abci_app.md b/docs/api/skills/abstract_round_abci/test_tools/abci_app.md index c7a2e11c1c..0a17fd6e76 100644 --- a/docs/api/skills/abstract_round_abci/test_tools/abci_app.md +++ b/docs/api/skills/abstract_round_abci/test_tools/abci_app.md @@ -94,6 +94,16 @@ class ConcreteBackgroundRound(_ConcreteRound) Dummy instantiation of the AbstractRound class. + + +## ConcreteBackgroundSlashingRound Objects + +```python +class ConcreteBackgroundSlashingRound(_ConcreteRound) +``` + +Dummy instantiation of the AbstractRound class. + ## ConcreteTerminationRoundA Objects @@ -124,6 +134,26 @@ class ConcreteTerminationRoundC(_ConcreteRound) Dummy instantiation of the AbstractRound class. + + +## ConcreteSlashingRoundA Objects + +```python +class ConcreteSlashingRoundA(_ConcreteRound) +``` + +Dummy instantiation of the AbstractRound class. + + + +## ConcreteSlashingRoundB Objects + +```python +class ConcreteSlashingRoundB(_ConcreteRound) +``` + +Dummy instantiation of the AbstractRound class. + ## ConcreteEvents Objects @@ -144,6 +174,26 @@ def __str__() -> str Get the string representation of the event. + + +## TerminationAppTest Objects + +```python +class TerminationAppTest(AbciApp[ConcreteEvents]) +``` + +A dummy Termination abci for testing purposes. + + + +## SlashingAppTest Objects + +```python +class SlashingAppTest(AbciApp[ConcreteEvents]) +``` + +A dummy Slashing abci for testing purposes. + ## AbciAppTest Objects diff --git a/docs/api/skills/abstract_round_abci/utils.md b/docs/api/skills/abstract_round_abci/utils.md index b6b5555e1b..7a6a0844f8 100644 --- a/docs/api/skills/abstract_round_abci/utils.md +++ b/docs/api/skills/abstract_round_abci/utils.md @@ -165,6 +165,12 @@ def __str__() -> str Get string representation of AutonomyTypeError. + + +#### Result + +returns error context + #### check @@ -363,3 +369,13 @@ Get consensus threshold. the consensus threshold + + +#### inverse + +```python +def inverse(dict_: Dict[KeyType, ValueType]) -> Dict[ValueType, List[KeyType]] +``` + +Get the inverse of a dictionary. + diff --git a/docs/api/skills/registration_abci/behaviours.md b/docs/api/skills/registration_abci/behaviours.md index 04fe0b96f2..e502eb6551 100644 --- a/docs/api/skills/registration_abci/behaviours.md +++ b/docs/api/skills/registration_abci/behaviours.md @@ -2,7 +2,13 @@ # packages.valory.skills.registration`_`abci.behaviours -This module contains the behaviours for the 'abci' skill. +This module contains the behaviours for the 'registration_abci' skill. + + + +#### WAIT`_`FOR`_`BLOCK`_`TIMEOUT + +1 minute diff --git a/docs/api/skills/transaction_settlement_abci/models.md b/docs/api/skills/transaction_settlement_abci/models.md index ae5f4c6996..7251d8c5de 100644 --- a/docs/api/skills/transaction_settlement_abci/models.md +++ b/docs/api/skills/transaction_settlement_abci/models.md @@ -25,6 +25,17 @@ class MutableParams(TypeCheckMixin) Collection for the mutable parameters. + + +## GasParams Objects + +```python +@dataclass +class GasParams(BaseParams) +``` + +Gas parameters. + ## TransactionParams Objects diff --git a/docs/api/skills/transaction_settlement_abci/payload_tools.md b/docs/api/skills/transaction_settlement_abci/payload_tools.md index 1b39f07f6a..faf36aece7 100644 --- a/docs/api/skills/transaction_settlement_abci/payload_tools.md +++ b/docs/api/skills/transaction_settlement_abci/payload_tools.md @@ -75,7 +75,9 @@ def hash_payload_to_hex(safe_tx_hash: str, safe_gas_price: int = 0, gas_token: str = NULL_ADDRESS, refund_receiver: str = NULL_ADDRESS, - use_flashbots: bool = False) -> str + use_flashbots: bool = False, + gas_limit: int = 0, + raise_on_failed_simulation: bool = False) -> str ``` Serialise to a hex string. diff --git a/docs/api/skills/transaction_settlement_abci/rounds.md b/docs/api/skills/transaction_settlement_abci/rounds.md index 1481cf2931..6a2145ea9c 100644 --- a/docs/api/skills/transaction_settlement_abci/rounds.md +++ b/docs/api/skills/transaction_settlement_abci/rounds.md @@ -257,6 +257,16 @@ def participant_to_late_messages( Get the mapping from participants to checks. + + +#### get`_`chain`_`id + +```python +def get_chain_id(default_chain_id: str) -> str +``` + +Get the chain id. + ## FailedRound Objects @@ -518,7 +528,7 @@ Transition states: - done: 11. - negative: 5. - none: 6. - - validate timeout: 6. + - validate timeout: 5. - no majority: 4. 5. CheckTransactionHistoryRound - done: 11. diff --git a/docs/application_deployment.md b/docs/application_deployment.md index 7fbb01b86a..87c11e9099 100644 --- a/docs/application_deployment.md +++ b/docs/application_deployment.md @@ -38,7 +38,6 @@ Options: --remote To use a remote registry. --local To use a local registry. -p Ask for password interactively - --password PASSWORD Set password for key encryption/decryption --help Show this message and exit. ``` @@ -52,7 +51,7 @@ Usage: autonomy build-image [OPTIONS] [PUBLIC_ID_OR_HASH] Options: --service-dir PATH Path to service dir. - --dev Build developement image. + --dev Build development image. --pull Pull latest dependencies. --help Show this message and exit. diff --git a/docs/configure_service/analise_test.md b/docs/configure_service/analise_test.md index 34e019830e..5a1e11d975 100644 --- a/docs/configure_service/analise_test.md +++ b/docs/configure_service/analise_test.md @@ -50,8 +50,7 @@ The `valory/abstract_round_abci` skill packages come with a number of testing to Fetch the `hello_world` agent, which comes with the `hello_world_abci` {{fsm_app}} skill within: ```bash - autonomy fetch valory/hello_world:0.1.0:bafybeidghah5yexnsdxwplnbyq3u3bgl2mmjur2eef4bxenf6ddb3zs2ca - mv hello_world hello_world_agent + autonomy fetch valory/hello_world:0.1.0:bafybeib5grnum25svkpozqqnvpd7nmwoaypnc3l7lbnoj335nwgczsiyca --alias hello_world_agent ``` Look at the unit tests for the `hello_world_abci` skill, located in the folder @@ -77,8 +76,7 @@ The same plugin also provides tools for writing end-to-end tests for agents. The Fetch the `hello_world` agent: ```bash - autonomy fetch valory/hello_world:0.1.0:bafybeidghah5yexnsdxwplnbyq3u3bgl2mmjur2eef4bxenf6ddb3zs2ca - mv hello_world hello_world_agent + autonomy fetch valory/hello_world:0.1.0:bafybeib5grnum25svkpozqqnvpd7nmwoaypnc3l7lbnoj335nwgczsiyca --alias hello_world_agent ``` Look at the end-to-end tests, located in the folder @@ -87,5 +85,5 @@ The same plugin also provides tools for writing end-to-end tests for agents. The ./hello_world_agent/tests/ ``` -The framework also provides CLI tools for building and running [local testing deployments](../guides/deploy_service.md#local-deployment). +The framework also provides CLI tools for building and running [local testing deployments](../guides/deploy_service.md#local-deployment-full-workflow). You can include additional images in your testing deployment, for example, a Hardhat node with custom contracts, or an ACN node. This is achieved through the flags `--use-hardhat` and `--use-acn`, respectively. Read the [`autonomy deploy build` command documentation](../advanced_reference/commands/autonomy_deploy.md#autonomy-deploy-build) and the guide for [using custom images in a deployment](../advanced_reference/use_custom_images.md#images-used-in-testing-only) for more information. diff --git a/docs/configure_service/configure_access_external_chains.md b/docs/configure_service/configure_access_external_chains.md index 546af4cda7..cbb25328a1 100644 --- a/docs/configure_service/configure_access_external_chains.md +++ b/docs/configure_service/configure_access_external_chains.md @@ -29,8 +29,8 @@ At agent level, the agent configuration file `aea-config.yaml` should contain an === "Using environment variables (recommended)" - ```yaml - (...) + ```yaml title="aea-config.yaml" + # (...) --- public_id: valory/ledger:0.19.0 type: connection @@ -43,8 +43,8 @@ At agent level, the agent configuration file `aea-config.yaml` should contain an ``` === "Using hardcoded values" - ```yaml - (...) + ```yaml title="aea-config.yaml" + # (...) --- public_id: valory/ledger:0.19.0 type: connection @@ -66,8 +66,8 @@ On the other hand agent-level environment variable overrides must follow the [ex Similarly, service-level overrides for the `valory/ledger` connection are defined in the service configuration file `service.yaml` using either approach: === "Using environment variables" - ```yaml - (...) + ```yaml title="service.yaml" + # (...) --- public_id: valory/ledger:0.19.0 type: connection @@ -81,8 +81,8 @@ Similarly, service-level overrides for the `valory/ledger` connection are define === "Using hardcoded values" - ```yaml - (...) + ```yaml title="service.yaml" + # (...) --- public_id: valory/ledger:0.19.0 type: connection @@ -189,7 +189,7 @@ The underlying retrial mechanism has a backoff that scales linearly, starting at An example configuration in the `skill.yaml` file for the Ethereum mainnet is as follows: ```yaml - (...) + # (...) models: params: args: diff --git a/docs/configure_service/on-chain_deployment_checklist.md b/docs/configure_service/on-chain_deployment_checklist.md index 7f480dd835..edee47eb62 100644 --- a/docs/configure_service/on-chain_deployment_checklist.md +++ b/docs/configure_service/on-chain_deployment_checklist.md @@ -17,7 +17,7 @@ You can define custom arguments for the skill, if required. from packages.valory.skills.abstract_round_abci.models import BenchmarkTool from packages.valory.skills.abstract_round_abci.models import BaseParams - (...) + # (...) YourBenchmarkTool = BenchmarkTool YourSkillParams = BaseParams @@ -29,7 +29,7 @@ You can define custom arguments for the skill, if required. from packages.valory.skills.abstract_round_abci.models import BenchmarkTool from packages.valory.skills.abstract_round_abci.models import BaseParams - (...) + # (...) YourBenchmarkTool = BenchmarkTool @@ -38,7 +38,7 @@ You can define custom arguments for the skill, if required. self.your_custom_arg_1: str = self._ensure("your_custom_arg_1", kwargs, str) self.your_custom_arg_2: str = self._ensure("your_custom_arg_2", kwargs, str) - (...) + # (...) super().__init__(*args, **kwargs) ``` @@ -64,7 +64,7 @@ See also the [service level overrides](../configure_service/service_configuratio author: version: type: skill - (...) + # (...) models: benchmark_tool: args: @@ -83,14 +83,14 @@ See also the [service level overrides](../configure_service/service_configuratio service_registry_address: null share_tm_config_on_startup: false on_chain_service_id: null - (...) + # (...) class_name: YourSkillParams ``` === "aea-config.yaml" ``` yaml - (...) + # (...) --- public_id: valory/abci:0.1.0 type: connection @@ -148,13 +148,13 @@ See also the [service level overrides](../configure_service/service_configuratio service_registry_address: ${str:null} share_tm_config_on_startup: ${bool:false} on_chain_service_id: ${int:null} - (...) + # (...) ``` === "service.yaml" ``` yaml - (...) + # (...) --- public_id: valory/ledger:0.19.0 type: connection @@ -185,12 +185,12 @@ See also the [service level overrides](../configure_service/service_configuratio service_registry_address: ${SERVICE_REGISTRY_ADDRESS:str:0x...} share_tm_config_on_startup: ${SHARE_TM_CONFIG_ON_STARTUP:bool:false} on_chain_service_id: ${ON_CHAIN_SERVICE_ID:int:1} - (...) + # (...) ``` !!! warning "Important" Recall that when [deploying an on-chain service](../guides/deploy_service.md#on-chain-deployment) using `autonomy deploy from-token`, a number of arguments (under `setup`) are overridden with the values registered in the Autonolas Protocol: - ```yaml - (...) + ```yaml title="service.yaml" + # (...) models: params: args: diff --git a/docs/configure_service/service_configuration_file.md b/docs/configure_service/service_configuration_file.md index 0f2d0e62d4..49cebcc2bf 100644 --- a/docs/configure_service/service_configuration_file.md +++ b/docs/configure_service/service_configuration_file.md @@ -7,9 +7,9 @@ The service configuration file `service.yaml` is typically composed of service-s ???+ example - Here is an example of the service configuration file of the [Hello World service](../demos/hello_world_demo.md): + Here is an example of the service configuration file of the [Hello World service](https://docs.autonolas.network/demos/hello-world/): - ```yaml + ```yaml title="service.yaml" name: hello_world author: valory version: 0.1.0 @@ -22,6 +22,7 @@ The service configuration file `service.yaml` is typically composed of service-s agent: valory/hello_world:0.1.0:bafybeihqzkncz7r563lfkots4fphb7abdymdna4ir7in7fsbzjtx6yyndq number_of_agents: 4 deployment: {} + dependencies: {} --- extra: benchmark_persistence_params: @@ -87,7 +88,9 @@ There are a number of mandatory attributes that define the service, which are su | `fingerprint_ignore_patterns` | Filename patterns to be ignored. | | `agent` | Canonical agent, in the form `::`. | | `number_of_agents` | Number of agent instances that the service is composed of. | | -| `deployment` | External deployment configuration for configuring external hosts and ports. | | +| `deployment` | External deployment configuration for [publishing container ports](#publish-container-ports). | | +| `dependencies` | Python dependencies to include in the runtime image [publishing container ports](#publish-container-ports). | | + ## Service-level overrides The {{open_aea}} framework already has the notion of [component overrides](https://open-aea.docs.autonolas.tech/overrides/): if a component uses another component, the former can override configuration values of the sub-component. @@ -95,9 +98,9 @@ The {{open_aea}} framework already has the notion of [component overrides](https Similarly, the {{open_autonomy}} framework has the notion of service-level overrides. You can define them in the service configuration file `service.yaml`, which will be used to generate the deployment environment for the agents. Service-level overrides follow the mandatory service-specific attributes, separated by `---`. -You can, for example, override the default `HELLO_WORLD!` string that each agent prints on their console in the [Hello World service](../demos/hello_world_demo.md), which is originally defined in the `hello_world_abci` skill. +You can, for example, override the default `HELLO_WORLD!` string that each agent prints on their console in the [Hello World service](https://docs.autonolas.network/demos/hello-world/), which is originally defined in the `hello_world_abci` skill. -```yaml +```yaml title="service.yaml" name: hello_world author: valory version: 0.1.0 @@ -148,8 +151,8 @@ You can define values for overridden attributes in two ways: You can override different values for different agents in the service configuration file with the multiple override feature, using the pattern below: -```yaml -(...) +```yaml title="service.yaml" +# (...) --- public_id: valory/hello_world_abci:0.1.0 type: skill @@ -162,10 +165,10 @@ type: skill ???+ example - If you wish that each agent outputs a different message in the [Hello World service](../demos/hello_world_demo.md) with four agents, you can define the following multiple override in the `service.yaml` file: + If you wish that each agent outputs a different message in the [Hello World service](https://docs.autonolas.network/demos/hello-world/) with four agents, you can define the following multiple override in the `service.yaml` file: - ```yaml - (...) + ```yaml title="service.yaml" + # (...) --- public_id: valory/hello_world_abci:0.1.0 type: skill @@ -197,8 +200,8 @@ If you have repetitive overridden parameters, you can define them using [YAML an In this example, we define a YAML anchor with label `&id001` to avoid repeating the same configuration of the `args` parameter in all the agents. - ```yaml - (...) + ```yaml title="service.yaml" + # (...) --- extra: benchmark_tool: @@ -249,8 +252,8 @@ Note that when deploying an agent service, environment variables are defined sep ???+ example If you have an override like - ```yaml - (...) + ```yaml title="service.yaml" + # (...) --- public_id: valory/hello_world_abci:0.1.0 type: skill @@ -262,8 +265,8 @@ Note that when deploying an agent service, environment variables are defined sep it will export the environment variable `SKILL_MODELS_PARAM_ARGS_HELLO_WORLD_MESSAGE`. On the other hand, if you use the multiple override feature and you have something like - ```yaml - (...) + ```yaml title="service.yaml" + # (...) --- public_id: valory/hello_world_abci:0.1.0 type: skill @@ -299,8 +302,8 @@ If you have nested lists the environment export rules will differ as per the inn ???+ example If you have an override like - ```yaml - (...) + ```yaml title="service.yaml" + # (...) --- public_id: vendor/hello_world_abci:0.1.0 type: skill @@ -331,8 +334,8 @@ If an overridden list contains mapping values, it will be exported as ???+ example If you have an override like - ```yaml - (...) + ```yaml title="service.yaml" + # (...) --- public_id: valory/hello_world_abci:0.1.0 type: skill @@ -350,8 +353,8 @@ If an overridden list contains mapping values, it will be exported as So when defining the agent/component level overrides you will have to explicitly define all the elements of the list like this: -```yaml -(...) +```yaml title="service.yaml" +# (...) --- public_id: valory/hello_world_abci:0.1.0 type: skill @@ -363,37 +366,65 @@ models: - key: ${::} ``` -## Configure external ports +## Publish container ports -To expose container ports to host machine ports use following configuration +We use a syntax similar to Docker for [port publishing](https://docs.docker.com/config/containers/container-networking/#published-ports). To expose agent container ports to host machine ports use the following configuration: -```yaml -(...) +```yaml title="service.yaml" +# (...) deployment: agent: ports: : - : + : + tendermint: + ports: + : + : ``` -For example if you want to map port `8080` of the agent 0 to `8081` of the host machine port you can use following configuration +Port publishing also works with [multiple overrides](#multiple-overrides). For example if you want to map port `8080` of agent 0 to port `8081` of the host machine, use: -```yaml -(...) +```yaml title="service.yaml" +# (...) deployment: agent: ports: 0: - 8080: 8081 + 8081: 8080 + tendermint: + ports: + 0: + 26656: 26656 ``` -You can also configure these using environment variables +You can also configure these mappings using environment variables: -```yaml -(...) +```yaml title="service.yaml" +# (...) deployment: agent: ports: 0: - 8080: ${AGENT_0_HTTP_PORT:int:8080} -``` \ No newline at end of file + 8081: ${AGENT_0_HTTP_PORT:int:8080} + tendermint: + ports: + 0: + 26656: ${TM_NODE_0_P2P_PORT:int:26656} +``` + +## Override agent/component dependencies + +Service level dependencies can be defined using following format + +```yaml title="service.yaml" +# (...) +dependencies: + pypi-package: + version: ==1.0.0 + git-package: + git: https://github.com/valory-xyz/open-autonomy + ref: 79342a93079648ef03ab5aaf14978068fc96587a +``` + +The dependencies defined at the service level will take priority over the dependencies defined at the agent or component level. This means, if you define some dependency `pypi-package==1.0.0` at the agent/component level and re-define it as `py-package==1.1.0` at the service level, `py-package==1.1.0` will get installed when building the agent image following the `service > agent > skill > connection > contract > protocol` priority order. diff --git a/docs/control_flow.md b/docs/control_flow.md index feaeb05b4b..3120cc0a4f 100644 --- a/docs/control_flow.md +++ b/docs/control_flow.md @@ -69,7 +69,7 @@ sequenceDiagram FlaskServer-->+TendermintProcess: starts_tendermint_process -This can viewed in the logs as; +This can be viewed in the logs as; ```bash tail -f /logs/node_0.txt diff --git a/docs/counter_example.md b/docs/counter_example.md index e4a04296f1..dfadb12d1d 100644 --- a/docs/counter_example.md +++ b/docs/counter_example.md @@ -1,7 +1,7 @@ # Counter Agent Service Demo This demo shows how to run an agent service implementing a counter. -It is simple example that illustrates how state-machine replication is achieved across different agents through the consensus gadget, which is Tendermint, in this case. Note that, unlike the remaining demos, due to its simplicity, the business logic of this service is not encoded as an {{fsm_app}}. Rather, it is implemented as a simple skill (`counter`) containing an `ABCIHandler`. The skill does not contain proactive behaviours, which means that no client calls are made to the consensus gadget. +It is a simple example that illustrates how state-machine replication is achieved across different agents through the consensus gadget, which is Tendermint, in this case. Note that, unlike the remaining demos, due to its simplicity, the business logic of this service is not encoded as an {{fsm_app}}. Rather, it is implemented as a simple skill (`counter`) containing an `ABCIHandler`. The skill does not contain proactive behaviours, which means that no client calls are made to the consensus gadget. ## Architecture of the Demo @@ -25,7 +25,7 @@ you have followed the [setup instructions](guides/quick_start.md#setup). As a re 2. Use the CLI to download the `valory/counter` service. ```bash - autonomy fetch valory/counter:0.1.0:bafybeihzpb3uz7gdclswkusnsbsjgnnmh7xbkwbulkxzpgjteqhfsynvzy --remote --service + autonomy fetch valory/counter:0.1.0:bafybeiehjaxonhm45oagbuqdrc46vgxfzo75bx7kjnejw55qbwfzjmpyfi --remote --service cd counter ``` @@ -127,7 +127,7 @@ The response to this HTTP request above is: } ``` -As you can see from the `log` field, the counter is initializes at `0`. +As you can see from the `log` field, the counter is initialized at `0`. `value` contains the `base64` encoding of the bytes of the data, representing the app state. @@ -277,14 +277,14 @@ returns the updated counter value: ### Interact through an AEA -In this section we will see an example on +In this section we will see an example of how to use an AEA to interact with the Tendermint network built above. First, open a terminal to the root of this repository, and fetch the `counter_client` agent: ```bash -autonomy fetch valory/counter_client:0.1.0:bafybeigp4ayq6lsjdeu4pltrksqwcd5lnoqpuhtwznzc5w5y75337ptfo4 --remote +autonomy fetch valory/counter_client:0.1.0:bafybeiczbvqzoaltjd6pfwskniwqigubkarbshk2khtrwaz5vb5biwvw44 --remote ``` This will copy the agent project in the `counter_client` directory. @@ -318,7 +318,7 @@ value of the counter; this behaviour is implemented in the The output of the run should be something like: -``` +```text _ _____ _ / \ | ____| / \ / _ \ | _| / _ \ @@ -349,5 +349,5 @@ info: [counter_client] [2021-08-05T20:00:14.838130] The counter value is: 3 info: [counter_client] [2021-08-05T20:00:15.826483] The counter value is: 4 info: [counter_client] [2021-08-05T20:00:15.826825] Update current state: 4 info: [counter_client] [2021-08-05T20:00:16.831485] The counter value is: 4 -... +(...) ``` diff --git a/docs/delegate_call.md b/docs/delegate_call.md deleted file mode 100644 index a78e9c8ebb..0000000000 --- a/docs/delegate_call.md +++ /dev/null @@ -1,3 +0,0 @@ -## Delegate call vs call - -Delegate call can be difficult to wrap your head around, but think of it this way: a delegate call means "load the code from this address and run it". This means that, when you create the Safe tx with operation=delegatecall, you are telling the Safe to get the code from the contract whose address is provided and execute it. \ No newline at end of file diff --git a/docs/demos/hello_world_demo.md b/docs/demos/hello_world_demo.md deleted file mode 100644 index 04b6cc8f3e..0000000000 --- a/docs/demos/hello_world_demo.md +++ /dev/null @@ -1,562 +0,0 @@ -The Hello World service provides an overview of the main components of an [agent service](../get_started/what_is_an_agent_service.md) and how they work together. The goal of this service is to help new users of Open Autonomy understand how the components of of a service work. While the service itself is very simple, it demonstrates common features found in many agent services and can be used as a starting point for building your own service with more complex functionalities. - -## Architecture of the demo - -The demo is composed of: - -* 4 Docker containers implementing the 4 agents of the service (`abci0`, `abci1`, `abci2`, `abci3`), and -* 4 Docker containers implementing a [Tendermint](https://tendermint.com/) node for each agent (`node0`, `node1`, `node2`, `node3`). - -The agents connect to the remote [DRAND](https://drand.love) service through the Internet during the execution -of the demo. - -
- ![](../images/hello_world_demo_architecture.svg){align=center} -
Hello World service demo architecture with four agents
-
- -## Running the demo - -You can find the instructions on how to run the Hello World service in the [quick start](../guides/quick_start.md) guide. - -If you have [set up the framework](../guides/set_up.md#set-up-the-framework), you can fetch the source code of the Hello World agent: - -```bash -autonomy fetch valory/hello_world:0.1.0:bafybeidghah5yexnsdxwplnbyq3u3bgl2mmjur2eef4bxenf6ddb3zs2ca -mv hello_world hello_world_agent -``` - -and the Hello World service: - -```bash -autonomy fetch valory/hello_world:0.1.0:bafybeigtaxh5zfg32cypqkjvftreivh22sqlrbgw5x3lxjmrf3dyqcioyy --service -mv hello_world hello_world_service -``` - -## Details of the demo - -The functionality of the service is extremely simple. Namely, each agent will output at different times a `HELLO_WORLD!` message on their local console. The execution timeline is divided into *periods*, and within each period, only a nominated agent (keeper) will print the `HELLO_WORLD!` message. The other agents will just print a neutral face `:|`. - -!!! info - - In the context of agent services, you can think of a *period* as an interval where the service executes an iteration of its intended functionality (e.g., checking some price on a market, execute an investment strategy, or in this demo, printing a message). - -Recall that agents synchronize their state using the *consensus gadget*. For clarity, we will simplify the consensus gadget infrastructure (the consensus gadget nodes plus the consensus gadget network) in a single green box. - -
-![](../images/hello_world_demo_architecture_simplified.svg){align="center"} -
A simplified view of the Hello world service architecture
-
- -!!! warning "Important" - - Every agent service is connected to the *consensus gadget* through its *consensus gadget node*: - - * The consensus gadget is the component that makes possible for the agents to synchronise state data. This allows them to, e.g. reach agreement on certain actions or reconcile information. - - * Anything happening at the consensus network level is completely abstracted away so that developers can see it as a given functionality. An application run by the agent service can be thought and developed as a single "virtual" application, and the framework will take care of replicating it. - - * Currently, the consensus gadget is implemented using [Tendermint](https://tendermint.com/). - -This is what the service execution looks like: - -
-![](../images/hello_world_action.svg) -
Hello World service in action
-
- -The main questions that we try to answer in the sections below are: - -* What are the main components of the {{open_autonomy}} framework to implement an agent service? -* How do these components work? - -### The FSM of the service - -As discussed in the [overview of the development process](../guides/overview_of_the_development_process.md), the first steps when designing an agent service are [draft the service idea and define the FSM specification](#) that represents its business logic. This is a representation of the Hello World service FSM: - -
-![](../images/hello_world_fsm.svg) -
Diagram of individual operations of the Hello World service
-
- -These are the states of the service: - -* **Registration.** This is a preliminary state where each agent commits to participate actively in the service. -* **CollectRandomness.** All agents connect to the [DRAND](https://drand.love) remote service and retrieve the latest published random value. -* **SelectKeeper.** Using that random value as seed, the agents nominate randomly an agent (keeper) to execute the service action. -* **PrintMessage.** The keeper executes the main action of the service: prints the `HELLO_WORLD!` message. -* **ResetAndPause.** A state where agents wait a bit before re-starting again the main cycle of the service. - -And these the possible events (not all events can occur at every state): - -* **DONE.** The state has successfully completed its intended purpose. -* **NO_MAJORITY.** There is no majority (more than 2/3) of agents that agree in the outcome of the state. -* **TIMEOUT.** Not all agents responded within a specified amount of time. - -You can see above how the service transits from one state to another given the event occurred at each one. The synchronized state enforced by the consensus gadget means that **all the agents have the same view of the service FSM**, and **all the agents execute the same transitions**. This is one of the key concepts of the {{open_autonomy}} framework. - -!!! warning "A note on determinism" - - One of the key points in an agent service is determinism. It is very important that all the agents execute deterministic actions at each step, otherwise it will be impossible to synchronize their shared state. - - For example, if the service needs to execute some random action, all agents must retrieve the random seed from a common source, in this case, the [DRAND](https://drand.love) service. - -Given the description of the service, it is immediate to obtain the FSM specification file. - -???+ example "The Hello World service `fsm_specification.yaml` file" - - ```yaml - alphabet_in: - - DONE - - NO_MAJORITY - - RESET_TIMEOUT - - ROUND_TIMEOUT - default_start_state: RegistrationRound - final_states: [] - label: HelloWorldAbciApp - start_states: - - RegistrationRound - states: - - CollectRandomnessRound - - PrintMessageRound - - RegistrationRound - - ResetAndPauseRound - - SelectKeeperRound - transition_func: - (CollectRandomnessRound, DONE): SelectKeeperRound - (CollectRandomnessRound, NO_MAJORITY): CollectRandomnessRound - (CollectRandomnessRound, ROUND_TIMEOUT): CollectRandomnessRound - (PrintMessageRound, DONE): ResetAndPauseRound - (PrintMessageRound, ROUND_TIMEOUT): RegistrationRound - (RegistrationRound, DONE): CollectRandomnessRound - (ResetAndPauseRound, DONE): CollectRandomnessRound - (ResetAndPauseRound, NO_MAJORITY): RegistrationRound - (ResetAndPauseRound, RESET_TIMEOUT): RegistrationRound - (SelectKeeperRound, DONE): PrintMessageRound - (SelectKeeperRound, NO_MAJORITY): RegistrationRound - (SelectKeeperRound, ROUND_TIMEOUT): RegistrationRound - ``` - -### The {{fsm_app}} of the service - -Each agent is composed of a number of components, namely, [connections](https://open-aea.docs.autonolas.tech/connection/), [protocols](https://open-aea.docs.autonolas.tech/protocol/), [contracts](https://open-aea.docs.autonolas.tech/contract/) and [skills](https://open-aea.docs.autonolas.tech/skill/). In order to become part of an agent service, the agent requires a special skill: the {{fsm_app}}. The **{{fsm_app}} skill** is the component that processes events,transits the states of the service FSM, and executes the actions of the service. - -
-![](../images/hello_world_zoom_agent.svg) -
Zoom on a Hello World service agent.
-
- -The {{fsm_app}} is a complex component that consists of a number of classes. Below we list the main ones. - -For each state of the service FSM: - -* A [`Behaviour`](../key_concepts/abci_app_async_behaviour.md): The class that executes the proactive action at each state. For example, cast a vote for a keeper, print a message on screen, send a transaction on a blockchain, etc. -* A [`Payload`](../key_concepts/abci_app_async_behaviour.md): The message exchanged between agents in the state to indicate completion of the action. For example, a message containing what keeper the agent is voting for. -* A [`Round`](../key_concepts/abci_app_abstract_round.md): The class that processes the input from the consensus gadget and outputs the appropriate events to make the next transition. For example, output the event DONE when all agents have cast they vote for a keeper. - -Additionally, the following two classes: - -* [`AbciApp`](../key_concepts/abci_app_class.md): The class that defines the FSM itself and the transitions between states according to the FSM. -* [`RoundBehaviour`](../key_concepts/abci_app_abstract_round_behaviour.md): The main class of the {{fsm_app}} skill, which aggregates the `AbciApp` and establishes a one-to-one relationship between the rounds and behaviours of each state. - -In summary, the Hello World service {{fsm_app}} requires 5 `Behaviours`, 5 `Payloads`, 5 `Rounds`, 1 `AbciApp` and 1 `RoundBehaviour`. - -!!! info "Canonical agents vs agent instances" - - All agents in a service are implemented by the same codebase. We call such codebase a _canonical agent_, and we call each of the actual instances an _agent instance_. We often use _agent_ for short when there is no risk of confusion and it is clear from the context which of the two terms we are referring to. - - Each agent instance in a service can be parameterized with their own set of keys, addresses and other required attributes. - -### How the {{fsm_app}} works - -Let us focus on what happens inside the {{fsm_app}} of an agent when the service is located in the SelectKeeper state and it transitions to the PrintMessage state. - -1. **Execute the action and prepare the payload.** The `SelectKeeperBehaviour` is in charge of two tasks: - - * Execute the intended action, that is, determine what agent will be voted for as the new keeper. The choice is made deterministically, based on the randomness retrieved from [DRAND](https://drand.love). - * Prepares the `SelectKeeperPayload`, which contains its selection. - - ![](../images/hello_world_sequence_1.svg) - -2. **Send the payload.** The `SelectKeeperBehaviour` is in charge sends the payload to the consensus gadget. - - ![](../images/hello_world_sequence_2.svg) - -3. **Reach consensus.** The consensus gadget reads all the agents' outputs, and ensures that all agents have the same consistent view. The gadget takes the responsibility of executing the consensus algorithm, which is abstracted away to the developer. The consensus gadget uses a short-lived blockchain to execute the consensus algorithm. - - ![](../images/hello_world_sequence_3.svg) - - !!! note - "Reaching consensus" does not mean that the consensus gadget ensures that all the agents send the same payload. Rather, it means that all the agents have a _consistent view_ on what payload was sent by each of them. In this particular case, however all agents cast the same vote. - -4. **Callback to the {{fsm_app}}.** Once the consensus phase is finished, the `SelectKeeperRound` receives a callback and processes the outputs. Based on that, it casts an event. In this case, if strictly more than $2/3$ of the agents voted for a certain keeper, it casts the event `DONE`. - - ![](../images/hello_world_sequence_4.svg) - -5. **Transition to the next state.** The event `DONE` is received by the `AbciApp` class, which executes the transition to the next state (PrintMessage). - - ![](../images/hello_world_sequence_5.svg) - -The executions of further state transitions can be easily mapped with what has been presented here for the transition SelectKeeper $\rightarrow$ PrintMessage. - -???+ example "Transition PrintMessage $\rightarrow$ ResetAndPause" - - Following the same steps as above, this is what would happen: - - 1. The `PrintMessageBehaviour`, executes the main functionality. For the chosen keeper, it will be printing the `HELLO_WORLD` message. The rest of the agents simply print a neutral face. -
- ![](../images/hello_world_result.svg) -
Result of the execution the second period of the Hello World service
-
- - 2. The `PrintMessageBehaviour` sends a `PrintMessagePayload` to the consensus gadget, indicating what was the message it printed by each agent. - 3. The consensus gadget executes the consensus protocol ensuring a consistent view for all the agents. - 4. The `PrintMessageRound` receives a callback, and after checking that all agents have responded it will produce the `DONE` event. - 5. The `AbciApp` processes the event `DONE`, and moves to the next state, ResetAndPause. - -!!! note - - Observe that whereas in the SelectKeeper state we expect that all agents output the same payload to the consensus gadget (the same keeper vote), in the PrintMessage state it is admissible that the agents send different values, because they print different things on their console. - - Other states might have different waiting conditions, for instance - - * wait until all agents respond with a (possibly) different value, or - * wait until more than a threshold of agents respond with the same value. - - When the waiting condition is not met during a certain time interval, a special timeout event is generated by the `Round`, and the developer is in charge of defining how the FSM will transit in that case. You can see some of these unexpected events in the FSM diagram above. - -### Bird's eye view -As a summary, find below an image which shows the main components of the agent and the skill related to the Hello World service presented in this overview. Of course, this is by no means the complete picture of what is inside an agent, but it should give a good intuition of what are the main elements that play a role in any agent service and how they interact. - -
-![](../images/hello_world_agent_internal.svg) -
Main components of an agent that play a role in an agent service. Red arrows indicate a high-level flow of messages when the agent is in the SelectKeeper state.
-
- -### Coding the Hello World service: a primer - -As detailed in the [overview of the development process](./../guides/overview_of_the_development_process.md), in order to create a service, you must: - -* code the {{fsm_app}} skill, -* define the agent, and -* define the service. - -We will explore this source code in the sections below, paying attention on the main parts that you should take into account. - -#### Exploring the {{fsm_app}} skill code - -Take a look at the structure of the {{fsm_app}} skill of the Hello World service (called `hello_world_abci`): - -``` -./hello_world_agent/vendor/valory/skills/hello_world_abci/ -| -├── __init__.py -├── behaviours.py -├── dialogues.py -├── fsm_specification.yaml -├── handlers.py -├── models.py -├── payloads.py -├── README.md -├── rounds.py -├── skill.yaml -└── tests/ -``` - -Note that the easiest way to start building a new {{fsm_app}} is by [using the {{fsm_app}} scaffold tool](../guides/code_fsm_app_skill.md), because it already populates many of these files. The most important files you should look at are: - -* **`behaviours.py`**: This file defines the `Behaviours`, which encode the proactive actions occurring at each state of the FSM. Each behaviour is one-to-one associated to a `Round`. It also contains the `HelloWorldRoundBehaviour` class, which can be thought as the "main" class for the skill behaviour. - - Each behaviour must: - - 1. Set the `matching_round` attribute to the corresponding `Round` class. - 2. Define the action executed in the state inside the method `async_act()`. - 3. Prepare the `Payload` associated with this state. The payload can be anything that other agents might find useful for the action in this or future states. - 4. Send the `Payload`, which the consensus gadget will be in charge of synchronizing with all the agents. - 5. Wait until the consensus gadget finishes its work, and mark the state `set_done()`. - - The last three steps above are common for all the `Behaviours`. - - ???- example "The `PrintMessageBehaviour` class" - - Class diagram: - -
-
- classDiagram - HelloWorldABCIBaseBehaviour <|-- PrintMessageBehaviour - BaseBehaviour <|-- HelloWorldABCIBaseBehaviour - IPFSBehaviour <|-- BaseBehaviour - AsyncBehaviour <|-- BaseBehaviour - CleanUpBehaviour <|-- BaseBehaviour - SimpleBehaviour <|-- IPFSBehaviour - Behaviour <|-- SimpleBehaviour - class AsyncBehaviour{ - +async_act()* - +async_act_wrapper()* - } - class HelloWorldABCIBaseBehaviour { - +syncrhonized_data() - +params() - } - class PrintMessageBehaviour{ - +behaviour_id = "print_message" - +matching_round = PrintMessageRound - +async_act() - } -
-
Hierarchy of the PrintMessageBehaviour class (some methods and fields are omitted)
-
- - The `HelloWorldABCIBaseBehaviour` is a convenience class, and the upper class in the hierarchy are abstract classes from the stack that facilitate re-usability of code when implementing the `Behaviour`. An excerpt of the `PrintMessageBehaviour` code is: - - ```python - class PrintMessageBehaviour(HelloWorldABCIBaseBehaviour, ABC): - """Prints the celebrated 'HELLO WORLD!' message.""" - - matching_round = PrintMessageRound - - def async_act(self) -> Generator: - """ - Do the action. - - Steps: - - Determine if this agent is the current keeper agent. - - Print the appropriate to the local console. - - Send the transaction with the printed message and wait for it to be mined. - - Wait until ABCI application transitions to the next round. - - Go to the next behaviour (set done event). - """ - - if ( - self.context.agent_address - == self.synchronized_data.most_voted_keeper_address - ): - message = self.params.hello_world_string - else: - message = ":|" - - printed_message = f"Agent {self.context.agent_name} (address {self.context.agent_address}) in period {self.synchronized_data.period_count} says: {message}" - - print(printed_message) - self.context.logger.info(f"printed_message={printed_message}") - - payload = PrintMessagePayload(self.context.agent_address, printed_message) - - yield from self.send_a2a_transaction(payload) - yield from self.wait_until_round_end() - - self.set_done() - ``` - - Once all the `Behaviours` are defined, you can define the `HelloWorldRoundBehaviour` class. This class follows a quite standard structure in all agent services, and the reader can easily infer what is it from the source code. - - ???- example "The `HelloWorldRoundBehaviour` class" - - ```python - class HelloWorldRoundBehaviour(AbstractRoundBehaviour): - """This behaviour manages the consensus stages for the Hello World abci app.""" - - initial_behaviour_cls = RegistrationBehaviour - abci_app_cls = HelloWorldAbciApp - behaviours: Set[Type[BaseBehaviour]] = { - RegistrationBehaviour, # type: ignore - CollectRandomnessBehaviour, # type: ignore - SelectKeeperBehaviour, # type: ignore - PrintMessageBehaviour, # type: ignore - ResetAndPauseBehaviour, # type: ignore - } - ``` - -* **`payloads.py`**: This file defines the payloads associated to the consensus engine for each of the states. `Payloads` are data objects, and carry almost no business logic. - - ???- example "The `PrintMessagePayload` class" - - ```python - @dataclass(frozen=True) - class PrintMessagePayload(BaseTxPayload): - """Represent a transaction payload of type 'randomness'.""" - - message: str - ``` - -* **`rounds.py`**: This file contains the implementation of the rounds associated to each state and the shared `SynchronizedData` class (the class that stores the service shared state). It also contains the declaration of the FSM events, and the `HelloWorldAbciApp`, which defines the transition function of the FSM. - - Each round must: - - 1. Inherit from one of the classes that determine what kind of consensus is expected at the associated sate: `CollectDifferentUntilAllRound`, `CollectSameUntilAllRound`, `CollectSameUntilThresholdRound`, etc. - 2. Set the `payload_class` attribute to the corresponding `Payload` class. - 3. Set other attributes required by the inherited class. - 4. Implement the `end_block()` method, which is called by the consensus gadget. This method must output the updated `SynchronizedData` and the event produced after evaluating the consensus result. - - ???- example "The `PrintMessageRound` class" - - Class diagram: - -
-
- classDiagram - AbstractRound <|-- CollectionRound - CollectionRound <|-- _CollectUntilAllRound - _CollectUntilAllRound <|-- CollectDifferentUntilAllRound - CollectDifferentUntilAllRound <|-- PrintMessageRound - HelloWorldABCIAbstractRound <|-- PrintMessageRound - AbstractRound <|-- HelloWorldABCIAbstractRound - class AbstractRound{ - +round_id - +payload_class - -_synchronized_data - +synchronized_data() - +end_block()* - +check_payload()* - +process_payload()* - } - class HelloWorldABCIAbstractRound{ - +synchronized_data() - -_return_no_majority_event() - } - class CollectionRound{ - -collection - +payloads() - +payloads_count() - +process_payload() - +check_payload() - } - class _CollectUntilAllRound{ - +check_payload() - +process_payload() - +collection_threshold_reached() - } - class CollectDifferentUntilAllRound{ - +check_payload() - } - class PrintMessageRound{ - +payload_class = PrintMessagePayload - +end_block() - } -
-
Hierarchy of the PrintMessageRound class (some methods and fields are omitted)
-
- - The `HelloWorldABCIAbstractRound` is a convenience class defined in the same file. The class `CollectDifferentUntilAllRound` is a helper class for rounds that expect that each agent sends a different message. In this case, the message to be sent is the agent printed by each agent, which will be obviously different for each agent (one of them will be the `HELLO_WORLD!` message, and the others will be empty messages). - - ```python - class PrintMessageRound(CollectDifferentUntilAllRound, HelloWorldABCIAbstractRound): - """A round in which the keeper prints the message""" - - payload_class = PrintMessagePayload - - def end_block(self) -> Optional[Tuple[BaseSynchronizedData, Event]]: - """Process the end of the block.""" - if self.collection_threshold_reached: - synchronized_data = self.synchronized_data.update( - participants=tuple(sorted(self.collection)), - printed_messages=sorted( - [ - cast(PrintMessagePayload, payload).message - for payload in self.collection.values() - ] - ), - synchronized_data_class=SynchronizedData, - ) - return synchronized_data, Event.DONE - return None - ``` - - If the successful condition occurs, the `end_block()` method returns the appropriate event (`DONE`) so that the `AbciApp` can process and transit to the next round. - - Observe that the `RegistrationRound` is very similar to the `PrintMessageRound`, as it simply has to collect the different addresses that each agent sends. On the other hand, the classes `CollectRandomnessRound` and `SelectKeeperRound` just require to define some parent classes attributes, as they execute fairly standard operations already available in the framework. - - After having defined all the `Rounds`, the `HelloWorldAbciApp` does not have much mystery. It simply defines the transitions from one state to another in the FSM, arranged as Python dictionaries. For example, - - ```python - SelectKeeperRound: { - Event.DONE: PrintMessageRound, - Event.NO_MAJORITY: RegistrationRound, - Event.ROUND_TIMEOUT: RegistrationRound, - }, - ``` - - denotes the three possible transitions from the `SelectKeeperRound` to the corresponding `Rounds`, according to the FSM depicted above. - -Whereas these are the main files to take into account, there are other files that are also required, and you can take a look: - -* **`skill.yaml`**: This is the skill specification file. It defines the sub-components (e.g. protocols, connections) required by the skill, as well as a number of configuration parameters. -* **`handlers.py`**: Defines the `Handlers` (implementing reactive actions) used by the skill. It is mandatory that the skill associated to an agent service implements a handler inherited from the `ABCIRoundHandler`. Other handlers are required according to the actions that the skill is performing (e.g., interacting with an HTTP server). As you can see by exploring the file, little coding is expected unless you need to implement a custom protocol. -* **`dialogues.py`**: It defines the dialogues associated to the protocols described in the `skill.yaml` configuration file. Again, not much coding is expected in most cases. -* **`models.py`**: It defines the models of the skill, which usually consist of the `SharedState` and the configuration parameters `Params` classes. The classes defined here are linked with the contents in the section `models` in the file `skill.yaml`. -* **`fsm_specification.yaml`**: The {{fsm_app}} specification file. It is used for checking the consistency of the implementation, and it can be used to verify the implementation or to [scaffold the {{fsm_app}}](../guides/code_fsm_app_skill.md) providing an initial structure. - -#### Exploring the agent definition code - -The agent configuration file `aea-config.yaml` is located in the root folder of the agent: - -``` -./hello_world_agent/ -| -├── __init__.py -├── aea-config.yaml -├── README.md -├── tests/ -└── vendor/ -``` - -Agents are defined through the {{open_aea}} library as YAML files, which specify what components the agent made of ([connections](https://open-aea.docs.autonolas.tech/connection/), [protocols](https://open-aea.docs.autonolas.tech/protocol/), [contracts](https://open-aea.docs.autonolas.tech/contract/) and [skills](https://open-aea.docs.autonolas.tech/skill/)). Recall that an agent requires the {{fsm_app}} skill to work in a service. - -This is an excerpt of the `aea-config.yaml` file: - -```yaml -# ... -connections: -- valory/abci:0.1.0:bafybeih2l6ssf5ebkvgbag3hx2pd22shytszqavveib2e2s6rv4va5khv4 -- valory/http_client:0.23.0:bafybeidykl4elwbcjkqn32wt5h4h7tlpeqovrcq3c5bcplt6nhpznhgczi -- valory/ipfs:0.1.0:bafybeihubpyw2t3bwncz3l7jt4gf5xvfydwmob463vvgf3ikkhlwxakm3m -- valory/ledger:0.19.0:bafybeicgfupeudtmvehbwziqfxiz6ztsxr5rxzvalzvsdsspzz73o5fzfi -- valory/p2p_libp2p_client:0.1.0:bafybeidwcobzb7ut3efegoedad7jfckvt2n6prcmd4g7xnkm6hp6aafrva -contracts: [] -protocols: -- open_aea/signing:1.0.0:bafybeibqlfmikg5hk4phzak6gqzhpkt6akckx7xppbp53mvwt6r73h7tk4 -- valory/abci:0.1.0:bafybeig3dj5jhsowlvg3t73kgobf6xn4nka7rkttakdb2gwsg5bp7rt7q4 -- valory/http:1.0.0:bafybeifyoio7nlh5zzyn5yz7krkou56l22to3cwg7gw5v5o3vxwklibhty -- valory/ipfs:0.1.0:bafybeic72ncgqbzoz2guj4p4yjqulid7mv6yroeh65hxznloamoveeg7hq -skills: -- valory/abstract_abci:0.1.0:bafybeifuclb6cikagtg2zn7dkjnnv3f7re2tfgzk6c4h3scgyzaaqeg55m -- valory/abstract_round_abci:0.1.0:bafybeigiolzp3i6b3wwuau3yv2h5udqape3i7of73mlm2d6ud22irlkbme -- valory/hello_world_abci:0.1.0:bafybeiccrdfvkbrwawroglielcn2pf6vhhz7hoba2ya46ryd5zpmk4al5u -# ... -``` - -It is mandatory that service agents include some of mandatory components: the `abci` connection, the `abci` protocol, the `abstract_abci` skill and the `abstract_round_abci` skill. - -Additionally, the agent can use other connections, protocols or skills, depending of its particular needs. In the example, the `http_client` connection and the `http` protocol allows the agent to interact with HTTP servers (although we are not using it in this service). Similarly, you can add the `ledger` connection and the `ledger_api` protocol in case the agent needs to interact with a blockchain. -It obviously contains the `hello_world_abci` skill, which is the {{fsm_app}} skill discussed above. - -Note that although it is possible to develop your own protocols and connections, the {{open_aea}} framework provides a number of typical ones which can be reused. Therefore, it is usual that the developer focuses most of its programming efforts in coding the particular skill(s) for their new agent. - -#### Exploring the service definition code - -The service configuration file `service.yaml` is located in the root folder of the service: - -``` -./hello_world_service/ -| -├── README.md -└── service.yaml -``` - -You can read the [dedicated section](../configure_service/service_configuration_file.md) to understand the structure and configuration of the `service.yaml` file. - -## Conclusion and further reading - -Even though printing `HELLO_WORLD!` on a local console is far from being an exciting functionality, the Hello World service shows a number of non-trivial elements that are key components in many agent services: - -* The service defines a sequence of individual, well-defined actions, whose execution in the appropriate order achieves the intended functionality. -* Agents have to interact with each other to execute each of those actions, and reach a consensus on a number of decisions at certain moments (e.g., which is the keeper agent that prints the message in each period). -* Agents execute actions on their own. In this simple example it just consists of printing a local message. -* Agents have to use a shared, global store for persistent data (e.g., which was the last agent that printed the message). -* Finally, the service can progress even if some agent is faulty or malicious (up to a certain threshold of malicious agents). - -In this toy example we are not verifying that the keeper behaves honestly: there is no way for the other agents to verify its console. However, in a real service that implements some critical operation (e.g., like sending a transaction to a blockchain) further verification and security mechanisms have to be put in place. - -This walk-through, together with the [overview of the development process](../guides/overview_of_the_development_process.md) should give you some confidence to start creating your first service. Obviously, there are more elements in the {{open_autonomy}} framework that facilitate building complex applications by enabling to interact with blockchains and other networks. We refer the reader to the more advanced sections of the documentation (e.g., key concepts) where we explore in detail the components of the stack. - diff --git a/docs/demos/index.md b/docs/demos/index.md deleted file mode 100644 index f1f559e707..0000000000 --- a/docs/demos/index.md +++ /dev/null @@ -1,10 +0,0 @@ -#Demo agent services - index -Here you can find a number of already deployed services that showcase the potential -of the {{open_autonomy}} framework. You can fetch the services (and/or -the corresponding agents) from the remote IPFS registry and explore them by yourself. - -- [Hello world agent service](hello_world_demo.md): a demo service to showcase - how to use the main components in an agent service, without external interactions. -- [Price oracle demo](price_oracle_intro.md): a full service implementing a - price oracle where each agent collects price estimates from a different source. - \ No newline at end of file diff --git a/docs/demos/price_oracle_fsms.md b/docs/demos/price_oracle_fsms.md deleted file mode 100644 index 6948f6c547..0000000000 --- a/docs/demos/price_oracle_fsms.md +++ /dev/null @@ -1,596 +0,0 @@ -# Price Oracle - Description of the FSMs - -For reference, we provide a high-level description of the FSMs that constitute -the Price Oracle demo using a simplified syntax. -The syntax should be easy to understand for a reader familiar with conventional -automata textbook notation. - -The aim of this syntax is to be used as a starting point in the design and -reasoning of an {{fsm_app}} without delving into the internals of the {{open_autonomy}} framework -itself. Hence, the usage of objects is minimized, and only strings are -used as identifiers. It can be used as a description language to translate a -specification into code, e.g., for agent development, or for conducting some -formal analysis using a model checker like SPIN. - -Each FSM object is defined by a collection of seven input parameters: - -* label (optional), -* states, -* default start state, -* allowed start states (e.g., when re-routing a transition from another FSM), -* final states, -* input alphabet (i.e., received events), -* transition function, expressed as a function that maps tuples of the form (S, E) to the resulting state S'. That is, upon receiving event E being at state S, the FSM will transit to state S'. - -The summary of the constituent FSMs is as follows: - - -| FSM | States | Start states | Final states | Events | Non-trivial transitions (*) | -|----------------------- |-------: |-------------: |-------------: |-------: |------------------------: | -| AgentRegistration | 4 | 2 | 2 | 3 | 3 | -| OracleDeployment | 5 | 1 | 1 | 8 | 14 | -| PriceAggregation | 9 | 1 | 1 | 4 | 9 | -| TransactionSubmission | 10 | 1 | 2 | 9 | 26 | -| ResetPauseAbciApp | 3 | 1 | 2 | 3 | 3 | -| **OracleAbciApp** | **21** | **2** | **0** | **12** | **66** | - - -(`*`) Transitions to a different state, i.e., not self-transitions. - -#### `AgentRegistrationAbciApp` FSM - -```yaml -alphabet_in: -- DONE -- NO_MAJORITY -default_start_state: RegistrationStartupRound -final_states: -- FinishedRegistrationRound -label: AgentRegistrationAbciApp -start_states: -- RegistrationRound -- RegistrationStartupRound -states: -- FinishedRegistrationRound -- RegistrationRound -- RegistrationStartupRound -transition_func: - (RegistrationRound, DONE): FinishedRegistrationRound - (RegistrationRound, NO_MAJORITY): RegistrationRound - (RegistrationStartupRound, DONE): FinishedRegistrationRound -``` - -
-
-stateDiagram-v2 - RegistrationRound --> FinishedRegistrationFFWRound:
DONE
- RegistrationStartupRound --> FinishedRegistrationRound:
DONE
- RegistrationStartupRound --> FinishedRegistrationFFWRound:
FAST_FORWARD
-
-
AgentRegistrationAbciApp FSM
-
- - -#### `OracleDeploymentAbciApp` FSM -```yaml -alphabet_in: -- DEPLOY_TIMEOUT -- DONE -- FAILED -- NEGATIVE -- NONE -- NO_MAJORITY -- ROUND_TIMEOUT -- VALIDATE_TIMEOUT -default_start_state: RandomnessOracleRound -final_states: -- FinishedOracleRound -label: packages.valory.skills.oracle_deployment_abci.rounds.OracleDeploymentAbciApp -start_states: -- RandomnessOracleRound -states: -- DeployOracleRound -- FinishedOracleRound -- RandomnessOracleRound -- SelectKeeperOracleRound -- ValidateOracleRound -transition_func: - (DeployOracleRound, DEPLOY_TIMEOUT): SelectKeeperOracleRound - (DeployOracleRound, DONE): ValidateOracleRound - (DeployOracleRound, FAILED): SelectKeeperOracleRound - (RandomnessOracleRound, DONE): SelectKeeperOracleRound - (RandomnessOracleRound, NO_MAJORITY): RandomnessOracleRound - (RandomnessOracleRound, ROUND_TIMEOUT): RandomnessOracleRound - (SelectKeeperOracleRound, DONE): DeployOracleRound - (SelectKeeperOracleRound, NO_MAJORITY): RandomnessOracleRound - (SelectKeeperOracleRound, ROUND_TIMEOUT): RandomnessOracleRound - (ValidateOracleRound, DONE): FinishedOracleRound - (ValidateOracleRound, NEGATIVE): RandomnessOracleRound - (ValidateOracleRound, NONE): RandomnessOracleRound - (ValidateOracleRound, NO_MAJORITY): RandomnessOracleRound - (ValidateOracleRound, VALIDATE_TIMEOUT): RandomnessOracleRound -``` - -
-
-stateDiagram-v2 - RandomnessOracleRound --> SelectKeeperOracleRound:
DONE
- RandomnessOracleRound --> RandomnessOracleRound:
NO_MAJORITY
ROUND_TIMEOUT
- DeployOracleRound --> SelectKeeperOracleRound:
FAILED
DEPLOY_TIMEOUT
- DeployOracleRound --> ValidateOracleRound:
DONE
- SelectKeeperOracleRound --> DeployOracleRound:
DONE
- SelectKeeperOracleRound --> RandomnessOracleRound:
NO_MAJORITY
ROUND_TIMEOUT
- ValidateOracleRound --> FinishedOracleRound:
DONE
- ValidateOracleRound --> RandomnessOracleRound:
NO_MAJORITY
NONE
NEGATIVE
VALIDATE_TIMEOUT
-
-
OracleDeploymentAbciApp FSM
-
- -#### `PriceAggregationAbciApp` FSM -```yaml -alphabet_in: -- DONE -- NONE -- NO_MAJORITY -- ROUND_TIMEOUT -default_start_state: CollectObservationRound -final_states: -- FinishedPriceAggregationRound -label: packages.valory.skills.price_estimation_abci.rounds.PriceAggregationAbciApp -start_states: -- CollectObservationRound -states: -- CollectObservationRound -- EstimateConsensusRound -- FinishedPriceAggregationRound -- TxHashRound -transition_func: - (CollectObservationRound, DONE): EstimateConsensusRound - (CollectObservationRound, NO_MAJORITY): CollectObservationRound - (CollectObservationRound, ROUND_TIMEOUT): CollectObservationRound - (EstimateConsensusRound, DONE): TxHashRound - (EstimateConsensusRound, NONE): CollectObservationRound - (EstimateConsensusRound, NO_MAJORITY): CollectObservationRound - (EstimateConsensusRound, ROUND_TIMEOUT): CollectObservationRound - (TxHashRound, DONE): FinishedPriceAggregationRound - (TxHashRound, NONE): CollectObservationRound - (TxHashRound, NO_MAJORITY): CollectObservationRound - (TxHashRound, ROUND_TIMEOUT): CollectObservationRound -``` - -
-
-stateDiagram-v2 - CollectObservationRound --> EstimateConsensusRound:
DONE
- CollectObservationRound --> CollectObservationRound:
ROUND_TIMEOUT
NO_MAJORITY
- EstimateConsensusRound --> TxHashRound:
DONE
- EstimateConsensusRound --> CollectObservationRound:
ROUND_TIMEOUT
NO_MAJORITY
- TxHashRound --> FinishedPriceAggregationRound:
DONE
- TxHashRound --> CollectObservationRound:
ROUND_TIMEOUT
NONE
NO_MAJORITY
-
-
PriceAggregationAbciApp FSM
-
- -#### `TransactionSubmissionAbciApp` FSM -```yaml -alphabet_in: -- CHECK_HISTORY -- CHECK_LATE_ARRIVING_MESSAGE -- CHECK_TIMEOUT -- DONE -- FINALIZATION_FAILED -- FINALIZE_TIMEOUT -- INCORRECT_SERIALIZATION -- INSUFFICIENT_FUNDS -- MISSED_AND_LATE_MESSAGES_MISMATCH -- NEGATIVE -- NONE -- NO_MAJORITY -- RESET_TIMEOUT -- ROUND_TIMEOUT -- VALIDATE_TIMEOUT -default_start_state: RandomnessTransactionSubmissionRound -final_states: -- FailedRound -- FinishedTransactionSubmissionRound -label: TransactionSubmissionAbciApp -start_states: -- RandomnessTransactionSubmissionRound -states: -- CheckLateTxHashesRound -- CheckTransactionHistoryRound -- CollectSignatureRound -- FailedRound -- FinalizationRound -- FinishedTransactionSubmissionRound -- RandomnessTransactionSubmissionRound -- ResetRound -- SelectKeeperTransactionSubmissionARound -- SelectKeeperTransactionSubmissionBRound -- SelectKeeperTransactionSubmissionBRoundAfterTimeout -- SynchronizeLateMessagesRound -- ValidateTransactionRound -transition_func: - (CheckLateTxHashesRound, CHECK_LATE_ARRIVING_MESSAGE): SynchronizeLateMessagesRound - (CheckLateTxHashesRound, CHECK_TIMEOUT): CheckLateTxHashesRound - (CheckLateTxHashesRound, DONE): FinishedTransactionSubmissionRound - (CheckLateTxHashesRound, NEGATIVE): FailedRound - (CheckLateTxHashesRound, NONE): FailedRound - (CheckLateTxHashesRound, NO_MAJORITY): FailedRound - (CheckTransactionHistoryRound, CHECK_LATE_ARRIVING_MESSAGE): SynchronizeLateMessagesRound - (CheckTransactionHistoryRound, CHECK_TIMEOUT): CheckTransactionHistoryRound - (CheckTransactionHistoryRound, DONE): FinishedTransactionSubmissionRound - (CheckTransactionHistoryRound, NEGATIVE): SelectKeeperTransactionSubmissionBRound - (CheckTransactionHistoryRound, NONE): FailedRound - (CheckTransactionHistoryRound, NO_MAJORITY): CheckTransactionHistoryRound - (CollectSignatureRound, DONE): FinalizationRound - (CollectSignatureRound, NO_MAJORITY): ResetRound - (CollectSignatureRound, ROUND_TIMEOUT): CollectSignatureRound - (FinalizationRound, CHECK_HISTORY): CheckTransactionHistoryRound - (FinalizationRound, CHECK_LATE_ARRIVING_MESSAGE): SynchronizeLateMessagesRound - (FinalizationRound, DONE): ValidateTransactionRound - (FinalizationRound, FINALIZATION_FAILED): SelectKeeperTransactionSubmissionBRound - (FinalizationRound, FINALIZE_TIMEOUT): SelectKeeperTransactionSubmissionBRoundAfterTimeout - (FinalizationRound, INSUFFICIENT_FUNDS): SelectKeeperTransactionSubmissionBRound - (RandomnessTransactionSubmissionRound, DONE): SelectKeeperTransactionSubmissionARound - (RandomnessTransactionSubmissionRound, NO_MAJORITY): RandomnessTransactionSubmissionRound - (RandomnessTransactionSubmissionRound, ROUND_TIMEOUT): RandomnessTransactionSubmissionRound - (ResetRound, DONE): RandomnessTransactionSubmissionRound - (ResetRound, NO_MAJORITY): FailedRound - (ResetRound, RESET_TIMEOUT): FailedRound - (SelectKeeperTransactionSubmissionARound, DONE): CollectSignatureRound - (SelectKeeperTransactionSubmissionARound, INCORRECT_SERIALIZATION): FailedRound - (SelectKeeperTransactionSubmissionARound, NO_MAJORITY): ResetRound - (SelectKeeperTransactionSubmissionARound, ROUND_TIMEOUT): SelectKeeperTransactionSubmissionARound - (SelectKeeperTransactionSubmissionBRound, DONE): FinalizationRound - (SelectKeeperTransactionSubmissionBRound, INCORRECT_SERIALIZATION): FailedRound - (SelectKeeperTransactionSubmissionBRound, NO_MAJORITY): ResetRound - (SelectKeeperTransactionSubmissionBRound, ROUND_TIMEOUT): SelectKeeperTransactionSubmissionBRound - (SelectKeeperTransactionSubmissionBRoundAfterTimeout, CHECK_HISTORY): CheckTransactionHistoryRound - (SelectKeeperTransactionSubmissionBRoundAfterTimeout, CHECK_LATE_ARRIVING_MESSAGE): SynchronizeLateMessagesRound - (SelectKeeperTransactionSubmissionBRoundAfterTimeout, DONE): FinalizationRound - (SelectKeeperTransactionSubmissionBRoundAfterTimeout, INCORRECT_SERIALIZATION): FailedRound - (SelectKeeperTransactionSubmissionBRoundAfterTimeout, NO_MAJORITY): ResetRound - (SelectKeeperTransactionSubmissionBRoundAfterTimeout, ROUND_TIMEOUT): SelectKeeperTransactionSubmissionBRoundAfterTimeout - (SynchronizeLateMessagesRound, DONE): CheckLateTxHashesRound - (SynchronizeLateMessagesRound, MISSED_AND_LATE_MESSAGES_MISMATCH): FailedRound - (SynchronizeLateMessagesRound, NONE): SelectKeeperTransactionSubmissionBRound - (SynchronizeLateMessagesRound, NO_MAJORITY): SynchronizeLateMessagesRound - (SynchronizeLateMessagesRound, ROUND_TIMEOUT): SynchronizeLateMessagesRound - (ValidateTransactionRound, DONE): FinishedTransactionSubmissionRound - (ValidateTransactionRound, NEGATIVE): CheckTransactionHistoryRound - (ValidateTransactionRound, NONE): SelectKeeperTransactionSubmissionBRound - (ValidateTransactionRound, NO_MAJORITY): ValidateTransactionRound - (ValidateTransactionRound, VALIDATE_TIMEOUT): SelectKeeperTransactionSubmissionBRound -``` - -
-
-stateDiagram-v2 - RandomnessTransactionSubmissionRound --> SelectKeeperTransactionSubmissionARound:
DONE
- RandomnessTransactionSubmissionRound --> RandomnessTransactionSubmissionRound:
NO_MAJORITY
- RandomnessTransactionSubmissionRound --> ResetRound:
ROUND_TIMEOUT
- CheckLateTxHashesRound --> FinishedTransactionSubmissionRound:
DONE
- CheckLateTxHashesRound --> FailedRound:
NONE
NEGATIVE
NO_MAJORITY
- CheckLateTxHashesRound --> CheckLateTxHashesRound:
ROUND_TIMEOUT
- CheckTransactionHistoryRound --> SynchronizeLateMessagesRound:
CHECK_LATE_ARRIVING_MESSAGE
- CheckTransactionHistoryRound --> FinishedTransactionSubmissionRound:
DONE
- CheckTransactionHistoryRound --> FailedRound:
NONE
NEGATIVE
NO_MAJORITY
- CheckTransactionHistoryRound --> CheckTransactionHistoryRound:
ROUND_TIMEOUT
- CollectSignatureRound --> FinalizationRound:
DONE
- CollectSignatureRound --> ResetRound:
ROUND_TIMEOUT
NO_MAJORITY
- FinalizationRound --> CheckTransactionHistoryRound:
CHECK_HISTORY
- FinalizationRound --> SynchronizeLateMessagesRound:
CHECK_LATE_ARRIVING_MESSAGE
- FinalizationRound --> ValidateTransactionRound:
DONE
- FinalizationRound --> SelectKeeperTransactionSubmissionBRound:
FINALIZATION_FAILED
- FinalizationRound --> SelectKeeperTransactionSubmissionBRoundAfterTimeout:
ROUND_TIMEOUT
- ResetRound --> RandomnessTransactionSubmissionRound:
DONE
- ResetRound --> FailedRound:
NO_MAJORITY
RESET_TIMEOUT
- SelectKeeperTransactionSubmissionARound --> CollectSignatureRound:
DONE
- SelectKeeperTransactionSubmissionARound --> ResetRound:
ROUND_TIMEOUT
NO_MAJORITY
- SelectKeeperTransactionSubmissionBRound --> FinalizationRound:
DONE
- SelectKeeperTransactionSubmissionBRound --> ResetRound:
ROUND_TIMEOUT
NO_MAJORITY
- SelectKeeperTransactionSubmissionBRoundAfterTimeout --> CheckTransactionHistoryRound:
CHECK_HISTORY
- SelectKeeperTransactionSubmissionBRoundAfterTimeout --> FinalizationRound:
DONE
- SelectKeeperTransactionSubmissionBRoundAfterTimeout --> ResetRound:
ROUND_TIMEOUT
NO_MAJORITY
- SynchronizeLateMessagesRound --> CheckLateTxHashesRound:
DONE
- SynchronizeLateMessagesRound --> FailedRound:
NONE
MISSED_AND_LATE_MESSAGES_MISMATCH
- SynchronizeLateMessagesRound --> SynchronizeLateMessagesRound:
ROUND_TIMEOUT
NO_MAJORITY
- ValidateTransactionRound --> FinishedTransactionSubmissionRound:
DONE
- ValidateTransactionRound --> CheckTransactionHistoryRound:
NEGATIVE
- ValidateTransactionRound --> FinalizationRound:
VALIDATE_TIMEOUT
NONE
- ValidateTransactionRound --> ValidateTransactionRound:
NO_MAJORITY
-
-
TransactionSubmissionAbciApp FSM
-
- -#### `ResetPauseAbciApp` FSM - -```yaml -alphabet_in: -- DONE -- NO_MAJORITY -- RESET_AND_PAUSE_TIMEOUT -default_start_state: ResetAndPauseRound -final_states: -- FinishedResetAndPauseErrorRound -- FinishedResetAndPauseRound -label: ResetPauseAbciApp -start_states: -- ResetAndPauseRound -states: -- FinishedResetAndPauseErrorRound -- FinishedResetAndPauseRound -- ResetAndPauseRound -transition_func: - (ResetAndPauseRound, DONE): FinishedResetAndPauseRound - (ResetAndPauseRound, NO_MAJORITY): FinishedResetAndPauseErrorRound - (ResetAndPauseRound, RESET_AND_PAUSE_TIMEOUT): FinishedResetAndPauseErrorRound -``` - -
-
-stateDiagram-v2 - ResetAndPauseRound --> FinishedResetAndPauseRound:
DONE
- ResetAndPauseRound --> FinishedResetAndPauseErrorRound:
NO_MAJORITY
RESET_AND_PAUSE_TIMEOUT
-
-
ResetPauseAbciApp FSM
-
- - -#### `OracleAbciApp` FSM -As described above, the `OracleAbciApp` FSM is the composition of the -FSMs defined above using an FSM transition mapping that establishes the relationship -between the final states of a certain FSM with the start states of another FSM, that is, - -```python -OracleAbciApp = chain( - ( - AgentRegistrationAbciApp, - SafeDeploymentAbciApp, - OracleDeploymentAbciApp, - PriceAggregationAbciApp, - TransactionSubmissionAbciApp, - ResetPauseAbciApp, - ), - abci_app_transition_mapping, -) -``` -The transition mapping for this FSM is defined as - -```python -abci_app_transition_mapping: AbciAppTransitionMapping = { - FinishedRegistrationRound: RandomnessSafeRound, - FinishedSafeRound: RandomnessOracleRound, - FinishedOracleRound: CollectObservationRound, - FinishedRegistrationFFWRound: CollectObservationRound, - FinishedPriceAggregationRound: RandomnessTransactionSubmissionRound, - FailedRound: ResetAndPauseRound, - FinishedTransactionSubmissionRound: ResetAndPauseRound, - FinishedResetAndPauseRound: CollectObservationRound, - FinishedResetAndPauseErrorRound: RegistrationRound, -} -``` - - - -The complete specification of the composed FSM is therefore: - -```yaml -alphabet_in: -- CHECK_HISTORY -- CHECK_LATE_ARRIVING_MESSAGE -- CHECK_TIMEOUT -- DEPLOY_TIMEOUT -- DONE -- FAILED -- FAST_FORWARD -- FINALIZATION_FAILED -- FINALIZE_TIMEOUT -- INCORRECT_SERIALIZATION -- INSUFFICIENT_FUNDS -- MISSED_AND_LATE_MESSAGES_MISMATCH -- NEGATIVE -- NONE -- NO_MAJORITY -- RESET_AND_PAUSE_TIMEOUT -- RESET_TIMEOUT -- ROUND_TIMEOUT -- VALIDATE_TIMEOUT -default_start_state: RegistrationStartupRound -final_states: [] -label: packages.valory.skills.oracle_abci.composition.OracleAbciApp -start_states: -- RegistrationStartupRound -states: -- CheckLateTxHashesRound -- CheckTransactionHistoryRound -- CollectObservationRound -- CollectSignatureRound -- DeployOracleRound -- DeploySafeRound -- EstimateConsensusRound -- FinalizationRound -- RandomnessOracleRound -- RandomnessSafeRound -- RandomnessTransactionSubmissionRound -- RegistrationRound -- RegistrationStartupRound -- ResetAndPauseRound -- ResetRound -- SelectKeeperOracleRound -- SelectKeeperSafeRound -- SelectKeeperTransactionSubmissionARound -- SelectKeeperTransactionSubmissionBRound -- SelectKeeperTransactionSubmissionBRoundAfterTimeout -- SynchronizeLateMessagesRound -- TxHashRound -- ValidateOracleRound -- ValidateSafeRound -- ValidateTransactionRound -transition_func: - (CheckLateTxHashesRound, CHECK_LATE_ARRIVING_MESSAGE): SynchronizeLateMessagesRound - (CheckLateTxHashesRound, CHECK_TIMEOUT): CheckLateTxHashesRound - (CheckLateTxHashesRound, DONE): ResetAndPauseRound - (CheckLateTxHashesRound, NEGATIVE): ResetAndPauseRound - (CheckLateTxHashesRound, NONE): ResetAndPauseRound - (CheckLateTxHashesRound, NO_MAJORITY): ResetAndPauseRound - (CheckTransactionHistoryRound, CHECK_LATE_ARRIVING_MESSAGE): SynchronizeLateMessagesRound - (CheckTransactionHistoryRound, CHECK_TIMEOUT): CheckTransactionHistoryRound - (CheckTransactionHistoryRound, DONE): ResetAndPauseRound - (CheckTransactionHistoryRound, NEGATIVE): SelectKeeperTransactionSubmissionBRound - (CheckTransactionHistoryRound, NONE): ResetAndPauseRound - (CheckTransactionHistoryRound, NO_MAJORITY): CheckTransactionHistoryRound - (CollectObservationRound, DONE): EstimateConsensusRound - (CollectObservationRound, NO_MAJORITY): CollectObservationRound - (CollectObservationRound, ROUND_TIMEOUT): CollectObservationRound - (CollectSignatureRound, DONE): FinalizationRound - (CollectSignatureRound, NO_MAJORITY): ResetRound - (CollectSignatureRound, ROUND_TIMEOUT): CollectSignatureRound - (DeployOracleRound, DEPLOY_TIMEOUT): SelectKeeperOracleRound - (DeployOracleRound, DONE): ValidateOracleRound - (DeployOracleRound, FAILED): SelectKeeperOracleRound - (DeploySafeRound, DEPLOY_TIMEOUT): SelectKeeperSafeRound - (DeploySafeRound, DONE): ValidateSafeRound - (DeploySafeRound, FAILED): SelectKeeperSafeRound - (EstimateConsensusRound, DONE): TxHashRound - (EstimateConsensusRound, NONE): CollectObservationRound - (EstimateConsensusRound, NO_MAJORITY): CollectObservationRound - (EstimateConsensusRound, ROUND_TIMEOUT): CollectObservationRound - (FinalizationRound, CHECK_HISTORY): CheckTransactionHistoryRound - (FinalizationRound, CHECK_LATE_ARRIVING_MESSAGE): SynchronizeLateMessagesRound - (FinalizationRound, DONE): ValidateTransactionRound - (FinalizationRound, FINALIZATION_FAILED): SelectKeeperTransactionSubmissionBRound - (FinalizationRound, FINALIZE_TIMEOUT): SelectKeeperTransactionSubmissionBRoundAfterTimeout - (FinalizationRound, INSUFFICIENT_FUNDS): SelectKeeperTransactionSubmissionBRound - (RandomnessOracleRound, DONE): SelectKeeperOracleRound - (RandomnessOracleRound, NO_MAJORITY): RandomnessOracleRound - (RandomnessOracleRound, ROUND_TIMEOUT): RandomnessOracleRound - (RandomnessSafeRound, DONE): SelectKeeperSafeRound - (RandomnessSafeRound, NO_MAJORITY): RandomnessSafeRound - (RandomnessSafeRound, ROUND_TIMEOUT): RandomnessSafeRound - (RandomnessTransactionSubmissionRound, DONE): SelectKeeperTransactionSubmissionARound - (RandomnessTransactionSubmissionRound, NO_MAJORITY): RandomnessTransactionSubmissionRound - (RandomnessTransactionSubmissionRound, ROUND_TIMEOUT): RandomnessTransactionSubmissionRound - (RegistrationRound, DONE): CollectObservationRound - (RegistrationRound, NO_MAJORITY): RegistrationRound - (RegistrationStartupRound, DONE): RandomnessSafeRound - (RegistrationStartupRound, FAST_FORWARD): CollectObservationRound - (ResetAndPauseRound, DONE): CollectObservationRound - (ResetAndPauseRound, NO_MAJORITY): RegistrationRound - (ResetAndPauseRound, RESET_AND_PAUSE_TIMEOUT): RegistrationRound - (ResetRound, DONE): RandomnessTransactionSubmissionRound - (ResetRound, NO_MAJORITY): ResetAndPauseRound - (ResetRound, RESET_TIMEOUT): ResetAndPauseRound - (SelectKeeperOracleRound, DONE): DeployOracleRound - (SelectKeeperOracleRound, NO_MAJORITY): RandomnessOracleRound - (SelectKeeperOracleRound, ROUND_TIMEOUT): RandomnessOracleRound - (SelectKeeperSafeRound, DONE): DeploySafeRound - (SelectKeeperSafeRound, NO_MAJORITY): RandomnessSafeRound - (SelectKeeperSafeRound, ROUND_TIMEOUT): RandomnessSafeRound - (SelectKeeperTransactionSubmissionARound, DONE): CollectSignatureRound - (SelectKeeperTransactionSubmissionARound, INCORRECT_SERIALIZATION): ResetAndPauseRound - (SelectKeeperTransactionSubmissionARound, NO_MAJORITY): ResetRound - (SelectKeeperTransactionSubmissionARound, ROUND_TIMEOUT): SelectKeeperTransactionSubmissionARound - (SelectKeeperTransactionSubmissionBRound, DONE): FinalizationRound - (SelectKeeperTransactionSubmissionBRound, INCORRECT_SERIALIZATION): ResetAndPauseRound - (SelectKeeperTransactionSubmissionBRound, NO_MAJORITY): ResetRound - (SelectKeeperTransactionSubmissionBRound, ROUND_TIMEOUT): SelectKeeperTransactionSubmissionBRound - (SelectKeeperTransactionSubmissionBRoundAfterTimeout, CHECK_HISTORY): CheckTransactionHistoryRound - (SelectKeeperTransactionSubmissionBRoundAfterTimeout, CHECK_LATE_ARRIVING_MESSAGE): SynchronizeLateMessagesRound - (SelectKeeperTransactionSubmissionBRoundAfterTimeout, DONE): FinalizationRound - (SelectKeeperTransactionSubmissionBRoundAfterTimeout, INCORRECT_SERIALIZATION): ResetAndPauseRound - (SelectKeeperTransactionSubmissionBRoundAfterTimeout, NO_MAJORITY): ResetRound - (SelectKeeperTransactionSubmissionBRoundAfterTimeout, ROUND_TIMEOUT): SelectKeeperTransactionSubmissionBRoundAfterTimeout - (SynchronizeLateMessagesRound, DONE): CheckLateTxHashesRound - (SynchronizeLateMessagesRound, MISSED_AND_LATE_MESSAGES_MISMATCH): ResetAndPauseRound - (SynchronizeLateMessagesRound, NONE): SelectKeeperTransactionSubmissionBRound - (SynchronizeLateMessagesRound, NO_MAJORITY): SynchronizeLateMessagesRound - (SynchronizeLateMessagesRound, ROUND_TIMEOUT): SynchronizeLateMessagesRound - (TxHashRound, DONE): RandomnessTransactionSubmissionRound - (TxHashRound, NONE): CollectObservationRound - (TxHashRound, NO_MAJORITY): CollectObservationRound - (TxHashRound, ROUND_TIMEOUT): CollectObservationRound - (ValidateOracleRound, DONE): CollectObservationRound - (ValidateOracleRound, NEGATIVE): RandomnessOracleRound - (ValidateOracleRound, NONE): RandomnessOracleRound - (ValidateOracleRound, NO_MAJORITY): RandomnessOracleRound - (ValidateOracleRound, VALIDATE_TIMEOUT): RandomnessOracleRound - (ValidateSafeRound, DONE): RandomnessOracleRound - (ValidateSafeRound, NEGATIVE): RandomnessSafeRound - (ValidateSafeRound, NONE): RandomnessSafeRound - (ValidateSafeRound, NO_MAJORITY): RandomnessSafeRound - (ValidateSafeRound, VALIDATE_TIMEOUT): RandomnessSafeRound - (ValidateTransactionRound, DONE): ResetAndPauseRound - (ValidateTransactionRound, NEGATIVE): CheckTransactionHistoryRound - (ValidateTransactionRound, NONE): SelectKeeperTransactionSubmissionBRound - (ValidateTransactionRound, NO_MAJORITY): ValidateTransactionRound - (ValidateTransactionRound, VALIDATE_TIMEOUT): SelectKeeperTransactionSubmissionBRound -``` - -
-
-stateDiagram-v2 - RegistrationStartupRound --> RandomnessSafeRound:
DONE
- RegistrationStartupRound --> CollectObservationRound:
FAST_FORWARD
- CheckLateTxHashesRound --> ResetAndPauseRound:
DONE
- CheckLateTxHashesRound --> RegistrationRound:
NEGATIVE
NONE
NO_MAJORITY
- CheckLateTxHashesRound --> CheckLateTxHashesRound:
ROUND_TIMEOUT
- CheckTransactionHistoryRound --> SynchronizeLateMessagesRound:
CHECK_LATE_ARRIVING_MESSAGE
- CheckTransactionHistoryRound --> ResetAndPauseRound:
DONE
- CheckTransactionHistoryRound --> RegistrationRound:
NEGATIVE
NONE
NO_MAJORITY
- CheckTransactionHistoryRound --> CheckTransactionHistoryRound:
ROUND_TIMEOUT
- CollectObservationRound --> EstimateConsensusRound:
DONE
- CollectObservationRound --> CollectObservationRound:
ROUND_TIMEOUT
NO_MAJORITY
- CollectSignatureRound --> FinalizationRound:
DONE
- CollectSignatureRound --> ResetRound:
ROUND_TIMEOUT
NO_MAJORITY
- DeployOracleRound --> SelectKeeperOracleRound:
DEPLOY_TIMEOUT
FAILED
- DeployOracleRound --> ValidateOracleRound:
DONE
- DeploySafeRound --> SelectKeeperSafeRound:
DEPLOY_TIMEOUT
FAILED
- DeploySafeRound --> ValidateSafeRound:
DONE
- EstimateConsensusRound --> TxHashRound:
DONE
- EstimateConsensusRound --> CollectObservationRound:
ROUND_TIMEOUT
NO_MAJORITY
- FinalizationRound --> CheckTransactionHistoryRound:
CHECK_HISTORY
- FinalizationRound --> SynchronizeLateMessagesRound:
CHECK_LATE_ARRIVING_MESSAGE
- FinalizationRound --> ValidateTransactionRound:
DONE
- FinalizationRound --> SelectKeeperTransactionSubmissionBRound:
FINALIZATION_FAILED
- FinalizationRound --> SelectKeeperTransactionSubmissionBRoundAfterTimeout:
ROUND_TIMEOUT
- RandomnessOracleRound --> SelectKeeperOracleRound:
DONE
- RandomnessOracleRound --> RandomnessOracleRound:
ROUND_TIMEOUT
NO_MAJORITY
- RandomnessSafeRound --> SelectKeeperSafeRound:
DONE
- RandomnessSafeRound --> RandomnessSafeRound:
ROUND_TIMEOUT
NO_MAJORITY
- RandomnessTransactionSubmissionRound --> SelectKeeperTransactionSubmissionARound:
DONE
- RandomnessTransactionSubmissionRound --> RandomnessTransactionSubmissionRound:
NO_MAJORITY
- RandomnessTransactionSubmissionRound --> ResetRound:
ROUND_TIMEOUT
- RegistrationRound --> CollectObservationRound:
DONE
- ResetAndPauseRound --> CollectObservationRound:
DONE
- ResetAndPauseRound --> RegistrationRound:
RESET_AND_PAUSE_TIMEOUT
NO_MAJORITY
- ResetRound --> RandomnessTransactionSubmissionRound:
DONE
- ResetRound --> RegistrationRound:
RESET_TIMEOUT
NO_MAJORITY
- SelectKeeperOracleRound --> DeployOracleRound:
DONE
- SelectKeeperOracleRound --> RandomnessOracleRound:
ROUND_TIMEOUT
NO_MAJORITY
- SelectKeeperSafeRound --> DeploySafeRound:
DONE
- SelectKeeperSafeRound --> RandomnessSafeRound:
ROUND_TIMEOUT
NO_MAJORITY
- SelectKeeperTransactionSubmissionARound --> CollectSignatureRound:
DONE
- SelectKeeperTransactionSubmissionARound --> ResetRound:
ROUND_TIMEOUT
NO_MAJORITY
- SelectKeeperTransactionSubmissionBRound --> FinalizationRound:
DONE
- SelectKeeperTransactionSubmissionBRound --> ResetRound:
ROUND_TIMEOUT
NO_MAJORITY
- SelectKeeperTransactionSubmissionBRoundAfterTimeout --> CheckTransactionHistoryRound:
CHECK_HISTORY
- SelectKeeperTransactionSubmissionBRoundAfterTimeout --> FinalizationRound:
DONE
- SelectKeeperTransactionSubmissionBRoundAfterTimeout --> ResetRound:
ROUND_TIMEOUT
NO_MAJORITY
- SynchronizeLateMessagesRound --> CheckLateTxHashesRound:
DONE
- SynchronizeLateMessagesRound --> RegistrationRound:
NONE
MISSED_AND_LATE_MESSAGES_MISMATCH
- SynchronizeLateMessagesRound --> SynchronizeLateMessagesRound:
ROUND_TIMEOUT
NO_MAJORITY
- TxHashRound --> RandomnessTransactionSubmissionRound:
DONE
- TxHashRound --> CollectObservationRound:
ROUND_TIMEOUT
NONE
NO_MAJORITY
- ValidateOracleRound --> CollectObservationRound:
DONE
- ValidateOracleRound --> RandomnessOracleRound:
NEGATIVE
NONE
VALIDATE_TIMEOUT
NO_MAJORITY
- ValidateSafeRound --> RandomnessOracleRound:
DONE
- ValidateSafeRound --> RandomnessSafeRound:
NEGATIVE
NONE
VALIDATE_TIMEOUT
NO_MAJORITY
- ValidateTransactionRound --> ResetAndPauseRound:
DONE
- ValidateTransactionRound --> CheckTransactionHistoryRound:
NEGATIVE
- ValidateTransactionRound --> FinalizationRound:
NONE
VALIDATE_TIMEOUT
- ValidateTransactionRound --> ValidateTransactionRound:
NO_MAJORITY
-
-
OracleAbciApp FSM
-
diff --git a/docs/demos/price_oracle_intro.md b/docs/demos/price_oracle_intro.md deleted file mode 100644 index 5918162923..0000000000 --- a/docs/demos/price_oracle_intro.md +++ /dev/null @@ -1,164 +0,0 @@ -# Price Oracle Agent Service Demo - -The goal of this demo is to demonstrate an agent service that provides an estimation -of the Bitcoin price (USD) based on observations coming from different data sources, -e.g., CoinMarketCap, CoinGecko, Binance and Coinbase. -Each agent collects an observation from one of the data sources above and -shares it with the rest of the agents through the consensus gadget (Tendermint). -Once all the observations are settled, each agent -computes locally a deterministic function that aggregates the observations made by all the -agents, and obtains an estimate of the Bitcoin price. In this demo, we consider the -average of the observed values. -The local estimates made by all the agents are shared, and -a consensus is reached when one estimate -reaches $\lceil(2n + 1) / 3\rceil$ of the total voting power committed -on the consensus gadget. -Once the consensus on an estimate has been reached, a multi-signature transaction -with $\lceil(2n + 1) / 3\rceil$ of the participants' signatures is settled on the -Ethereum chain, which is emulated by a local Hardhat node in the demo. - - -## Architecture of the demo -This demo is composed of: - -- A [HardHat](https://hardhat.org/) node (emulating an Ethereum blockchain). -- A set of four [Tendermint](https://tendermint.com/) nodes (`node0`, `node1`, `node2`, `node3`). -- A set of four AEAs (`abci0`, `abci1`, `abci2`, `abci3`), in one-to-one connection with their corresponding Tendermint -node. - -
-![](../images/oracle_diagram.svg) -
Architecture of the Price Oracle demo
-
- - -## Running the demo - -Before running the demo, ensure that your machine satisfies the [framework requirements](../guides/set_up.md#requirements) and that -you have followed the [setup instructions](../guides/set_up.md#setup). As a result you should have a Pipenv workspace folder. - -To run the Price Oracle service follow the instructions in the [OracleKit section](https://docs.autonolas.network/product/oraclekit/#demo), which contains the necessary steps to download the service from the Service Registry, build and run a deployment locally with a local [HardHat](https://hardhat.org/) node. - - -## Interacting with the demo - -The logs of a single agent or [Tendermint](https://tendermint.com/) node can be inspected in another terminal with, e.g., - -```bash -docker logs --follow -``` - -where `` refers to the Docker container ID for either an agent -(`abci0`, `abci1`, `abci2` and `abci3`) or a [Tendermint](https://tendermint.com/) node (`node0`, `node1`, `node2` and `node3`). - -By examining the logs of an agent container, you will see a message similar to the one depicted below, after the framework successfully builds and starts it: - -``` - / \ | ____| / \ - / _ \ | _| / _ \ - / ___ \ | |___ / ___ \ -/_/ \_\|_____|/_/ \_\ - -v1.16.0 - -All available packages. -================================================================================ -| Package | IPFSHash | -================================================================================ - | | -(...) | | - | | -================================================================================ - -All instantiated components -====================================================== -| ComponentId | -====================================================== -| (protocol, valory/ledger_api:1.0.0) | -| (protocol, open_aea/signing:1.0.0) | -| (protocol, valory/acn:1.1.0) | -| (protocol, valory/http:1.0.0) | -| (protocol, valory/tendermint:0.1.0) | -| (protocol, valory/abci:0.1.0) | -| (protocol, valory/contract_api:1.0.0) | -| (connection, valory/abci:0.1.0) | -| (connection, valory/http_client:0.1.0) | -| (connection, valory/ledger:0.1.0) | -| (contract, valory/gnosis_safe_proxy_factory:0.1.0) | -| (contract, valory/gnosis_safe:0.1.0) | -| (contract, valory/offchain_aggregator:0.1.0) | -| (contract, valory/service_registry:0.1.0) | -| (skill, valory/oracle_abci:0.1.0) | -====================================================== - -All available addresses. -========================================================= -| Name | Address | -========================================================= -| ethereum | 0x15d34AAf54267DB7D7c367839AAf71A00a2C6A65 | -========================================================= -``` - -Following that, you will find the log messages indicating the different stages that the agent is currently executing: - -``` -Starting AEA 'agent' in 'async' mode... -[INFO] [agent] Entered in the 'registration_startup' round for period 0 -[INFO] [agent] Start processing messages... -[INFO] [agent] Entered in the 'registration_startup' behaviour -[INFO] [agent] Checking sync... -[INFO] [agent] Checking status @ http://node0:26657/status -[ERROR] [agent] Tendermint not accepting transactions yet, trying again! -[INFO] [agent] Checking status @ http://node0:26657/status -[ERROR] [agent] Tendermint not accepting transactions yet, trying again! -[INFO] [agent] Checking status @ http://node0:26657/status -[INFO] [agent] local height == remote == 0; Sync complete... -[INFO] [agent] Sharing Tendermint config on start-up?: False -[INFO] [agent] arrived block with timestamp: 2022-08-02 20:19:20.382918 -[INFO] [agent] current AbciApp time: None -[INFO] [agent] no pending timeout, move time forward -[INFO] Created a new local deadline for the next `begin_block` request from the Tendermint node: 2022-08-02 20:21:22.036121 -[INFO] [agent] arrived block with timestamp: 2022-08-02 20:20:21.841451 -[INFO] [agent] current AbciApp time: 2022-08-02 20:19:20.382918 -[INFO] [agent] no pending timeout, move time forward -[INFO] Created a new local deadline for the next `begin_block` request from the Tendermint node: 2022-08-02 20:21:23.463276 -[INFO] [agent] 'registration_startup' round is done with event: Event.DONE -[INFO] [agent] scheduling timeout of 7.0 seconds for event Event.ROUND_TIMEOUT with deadline 2022-08-02 20:20:28.841451 -[INFO] [agent] Entered in the 'randomness_safe' round for period 0 -[INFO] [agent] Entered in the 'randomness_safe' behaviour -[INFO] [agent] Retrieving DRAND values from api. -[INFO] [agent] Verifying DRAND values. -[INFO] [agent] DRAND check successful. -``` - -From the logs, you can see how the agent traverses the different states of the -{{fsm_app}}: registration, randomness collection, keeper selection, price collection, price estimation, etc. -For example, note how this particular agent collects the Bitcoin price from CoinGecko: - -``` -[INFO] [agent] Entered in the 'collect_observation' round for period 19 -[INFO] [agent] Entered in the 'collect_observation' behaviour -[INFO] [agent] Got observation of BTC price in USD from coingecko: 23112.0 -[INFO] [agent] arrived block with timestamp: 2022-08-02 22:51:16.858947 -[INFO] [agent] current AbciApp time: 2022-08-02 22:51:15.566192 -[INFO] Created a new local deadline for the next `begin_block` request from the Tendermint node: 2022-08-02 22:52:18.304367 -[INFO] [agent] 'collect_observation' round is done with event: Event.DONE -[INFO] [agent] scheduling timeout of 7.0 seconds for event Event.ROUND_TIMEOUT with deadline 2022-08-02 22:51:23.858947 -``` - -Afterwards, the agent estimate the price based on all the different observations collected and forwarded by all the agents: - -``` -[INFO] [agent] Entered in the 'estimate_consensus' round for period 19 -[INFO] [agent] Entered in the 'estimate' behaviour -[INFO] [agent] Got estimate of BTC price in USD: 23117.695, Using aggregator method: median -[INFO] [agent] arrived block with timestamp: 2022-08-02 22:51:18.194988 -[INFO] [agent] current AbciApp time: 2022-08-02 22:51:16.858947 -[INFO] Created a new local deadline for the next `begin_block` request from the Tendermint node: 2022-08-02 22:52:19.744814 -[INFO] [agent] 'estimate_consensus' round is done with event: Event.DONE -[INFO] [agent] scheduling timeout of 7.0 seconds for event Event.ROUND_TIMEOUT with deadline 2022-08-02 22:51:25.194988 -``` - -In order to fully understand what are the constituent states that the {{fsm_app}} is traversing, -we refer you to the [technical details](price_oracle_technical_details.md) of the demo, and also to -the [composition of FSMs](price_oracle_fsms.md) that make up the agents' {{fsm_app}}. diff --git a/docs/demos/price_oracle_technical_details.md b/docs/demos/price_oracle_technical_details.md deleted file mode 100644 index afd3c4cfe3..0000000000 --- a/docs/demos/price_oracle_technical_details.md +++ /dev/null @@ -1,299 +0,0 @@ -#Price Oracle - Technical Details - -Agents communicate directly to their local Tendermint node, whereas the `AbciApp` -is used to handle requests they receive (e.g., in response to their behaviour). - -In addition to other general-use components (e.g., signing, HTTP client), the components of the AEAs related to the implementation of the agent service are: - -- Protocol `valory/abci:0.1.0`: it allows representing - ABCI request and response messages. -- Connection `valory/abci:0.1.0`: it accepts ABCI requests - from a consensus engine module, e.g. the Tendermint node; -- Skill `valory/abstract_abci:0.1.0`: it provides a - scaffold handler for ABCI requests. It is an abstract skill. -- Skill `valory/abstract_round_abci:0.1.0`: it - implements an ABCI handler and provides - useful code abstractions for creating round-based - replicated state machines, based on the ABCI protocol - (e.g. `Period`, `AbstractRound`). It is an abstract skill. - -Moreover, it has the following specific components to implement the particular case of the price oracle agent service: - -- `valory/price_estimation_abci`: it implements the round-based - ABCI application for price estimation of a cryptocurrency, - with a finalization step over an Ethereum chain. - - -## The constituent {{fsm_app}}s - -The ABCI-based replicated FSM (`AbciApp`) used for price estimation consists -of several smaller modules, each of which is an `AbciApp` of its own. Each of -them is a `Skill`, which implies that they operate independently of each other, -however they can be combined to create a larger `AbciApp`, provided that the -developer specifies the required transition mapping to connect these FSMs. -This modularity allows a developer to use a subset of these skills in different -contexts, potentially in combination with skills they themselves define, to -create another composite `AbciApp` that performs according to their particular -needs. Specifically, the `PriceEstimationAbciApp` is created by combining the -following parts: - -- `AgentRegistrationAbciApp` -- `SafeDeploymentAbciApp` -- `OracleDeploymentAbciApp` -- `PriceAggregationAbciApp` -- `TransactionSubmissionAbciApp` -- `ResetPauseAbciApp` - -### The `AgentRegistrationAbciApp` - -This `AbciApp` implements the registration of agents to partake in the behaviour -scheduled in subsequent rounds. - -0. `RegistrationStartupRound`
- -1. `RegistrationRound`
- In this round registrations from AEAs to join the period are accepted, up to - a configured maximum number of participants (in the demo, this limit is 4); - once this threshold is hit ("registration threshold"), the round is finished. - -2. `FinishedRegistrationRound`
- A round that signals agent registration was successful, but service contracts has not been already deployed. - -3. `FinishedRegistrationFFWRound`
- A round that signals agent registration was successful, and the service contracts are already deployed. - - -### The `SafeDeploymentAbciApp` - -This `AbciApp` implements the deployments of a Gnosis safe contract, which is -a multisig smart contract wallet that requires a minimum number of people to -approve a transaction before it can occur. This assures that no single agent -can compromise the funds contained in it. - -0. `RandomnessSafeRound`
- Some randomness is retrieved to be used in a keeper agent selection. In - particular, agents individually request the latest random number from - [DRAND](https://drand.love), establish consensus on it and then use - it as a seed for computations requiring randomness (e.g. keeper selection). - -1. `SelectKeeperSafeRound`
- The agents agree on a new keeper that will be in charge of sending deploying - the multisig wallet and settling transactions. - -2. `DeploySafeRound`
- A designated sender among the participants of the current period deploys a - Gnosis Safe contract with all the - participants as owners and with `ceil((2n + 1) / 3)` as threshold. If the - safe deployment has not been completed after some time, a new keeper will be - selected and the safe deployment will be re-run. - -3. `ValidateSafeRound`
- All agents validate the previous deployment to ensure that the correct - contract with the correct settings has been deployed. If the safe deployment - could not be verified, the process will start again from the registration - round. - -4. `FinishedSafeRound`
- A round that signals the safe contract was deployed successfully. - - -### The `OracleDeploymentAbciApp` - -This `AbciApp` implements the deployments of an Oracle contract, a Gnosis safe -multisig smart contract wallet that was forked from [Chainlink](https://chain.link/) -and subsequently stripped from unnecessary data structures and behaviours. - -0. `RandomnessOracleRound`
- Similar as to the `RandomnessSafeRound`, randomness is retrieved here, this - time for the selection of an agent to become the oracle keeper. - -1. `SelectKeeperOracleRound`
- The agents select a new keeper that will be in charge of sending deploying - the multisig wallet and settling transactions. - -2. `DeployOracleRound`
- The designated keeper deploys a Gnosis safe contract. If a timeout occurs - before oracle deployment was completed, a new keeper will be selected and - the oracle deployment will be re-run. - -3. `ValidateOracleRound`
- all agents verify that the Oracle contract has been deployed using the - expected settings. If that's not the case, agents will restart the period. - -4. `FinishedOracleRound` - A round that signals the oracle contract was deployed successfully. - - -### The `PriceAggregationAbciApp` - -This `AbciApp` implements off-chain aggregation of observations by the agents. -Once the majority of agents has submitted their observation these are shared -with all agents as they move to the price estimation round. In this next round -each of the agents performs off-chain a computation on the data set, which could -be a simple summary statistic or an estimate derived from a complex model - -either way this is something that cannot be done on-chain. Once consensus is -reached on this estimate, the aggregate value is submitted and recorded -on-chain in the next block that is mined. - -0. `CollectObservationRound`
- Observational data is collected by the AEAs on the target quantity to - estimate. Once the agents reach consensus over this data, that is to say at - least 2/3rd of them agree on the set of single observations collected by - agents (not on individual observations), the shared state gets updated and - the agents enter the next round. - -1. `EstimateConsensusRound`
- Based on the collected data the actual price of the asset is estimated, which - could be a simple summary statistic such as the median or the geometric mean. - Once the same estimate receives a number of votes greater or equal than - 2/3 of the total voting power, consensus is reached and the period moves - forward. - -2. `TxHashRound`
- A designated sender composes the transaction and puts it on the temporary - Tendermint-based chain. Signing of the transaction for the multisig smart - contract requires consensus among the agents on the transaction hash to use. - -3. `FinishedPriceAggregationRound`
- A round that signals price aggregation was completed successfully. - - -### The `TransactionSubmissionAbciApp` - -0. `RandomnessTransactionSubmissionRound`
- Randomness is retrieved for keeper selection. - -1. `SelectKeeperTransactionSubmissionARound`
- The agents select a keeper that will be in charge of sending the transaction. - -2. `CollectSignatureRound`
- Agents sign the transaction to be submitted. - -3. `FinalizationRound`
- The keeper sends off the transaction to be incorporated in the next block. - A transaction hash is returned. This round takes care of submitting - with the right amount of gas, i.e., if resubmitting, then the "tip" for the miners - is also increased by 10%. - -4. `ValidateTransactionRound`
- Agents validate whether the transaction has been incorporated in the - blockchain. - -5. `CheckTransactionHistoryRound`
- This round is triggered if the `ValidateTransactionRound` returns with - a `NEGATIVE` `Event`, which means that the transaction has not been validated. - During the round, the agents check the transaction history up to this point again - in order to specify the cause of the problem, e.g., a transaction of a keeper - was settled before another keeper managed to do so, a payload is invalid, etc. - -6. `SelectKeeperTransactionSubmissionBRound`
- The agents select a keeper that will be in charge of sending the transaction, - in case that the first keeper has failed. - -7. `ResetRound`
- In case that a failure such as round timeout or no majority reached, the period - is reset. - -8. `ResetAndPauseRound`
- A round that updates the `SynchronizedData` to allocate a new period before going to the - `FinishedTransactionSubmissionRound`. - -9. `FinishedTransactionSubmissionRound`
- A round that signals transaction submission was completed successfully. - -10. `FailedRound`
- A round that signals transaction submission has failed. Occurs if the - `CheckTransactionHistoryRound` does not manage to find a validated transaction - in the history, or if a Reset round fails. - - -### Implementation of the `PriceEstimationAbciApp` - -In the final implementation the `PriceEstimationAbciApp` is then assembled from -its constituent parts. However, in order to combine the various FSMs previously -discussed, a transition mapping between states of these FSMs also needs to be -provided. In order to combine the different FSMs we need to connect them by -providing the necessary transition mapping. As per the code implemented in the -demo, the implementation looks as follows: - -```python -abci_app_transition_mapping: AbciAppTransitionMapping = { - FinishedRegistrationRound: RandomnessSafeRound, - FinishedSafeRound: RandomnessOracleRound, - FinishedOracleRound: CollectObservationRound, - FinishedRegistrationFFWRound: CollectObservationRound, - FinishedPriceAggregationRound: RandomnessTransactionSubmissionRound, - FailedRound: ResetAndPauseRound, - FinishedTransactionSubmissionRound: ResetAndPauseRound, - FinishedResetAndPauseRound: CollectObservationRound, - FinishedResetAndPauseErrorRound: RegistrationRound, -} - -OracleAbciApp = chain( - ( - AgentRegistrationAbciApp, - SafeDeploymentAbciApp, - OracleDeploymentAbciApp, - PriceAggregationAbciApp, - TransactionSubmissionAbciApp, - ResetPauseAbciApp, - ), - abci_app_transition_mapping, -) -``` - -Find below a graphical representation of this composition showing how the constituent FSMs interconnect to achieve the -functionality of the agent service in the demo. - -
-![](../images/oracle_composition.svg) -
Composition of the different FSMs that constitute the price oracle agent service FSM
-
- - -The AbstractRoundBehaviour schedules the state behaviour associated with the current round, ensuring that a transition to the new state cannot occur without first invoking the associated state Behaviour. Since it is composed of the Behaviours belonging to the constituent FSMs, we can reference them as depicted below. - - -```python -class OracleAbciAppConsensusBehaviour(AbstractRoundBehaviour): - """This behaviour manages the consensus stages for the price estimation.""" - - initial_behaviour_cls = RegistrationStartupBehaviour - abci_app_cls = OracleAbciApp # type: ignore - behaviours: Set[Type[BaseBehaviour]] = { - *OracleDeploymentRoundBehaviour.behaviours, - *AgentRegistrationRoundBehaviour.behaviours, - *SafeDeploymentRoundBehaviour.behaviours, - *TransactionSettlementRoundBehaviour.behaviours, - *ResetPauseABCIConsensusBehaviour.behaviours, - *ObserverRoundBehaviour.behaviours, - } -``` - -Have a look at the [FSM diagram](./price_oracle_fsms.md) of the application in order -to see what the encoded state transitions in the final composite FSM look like. - -!!! warning - - A sequence diagram that shows how AEAs communicate with their environment - throughout the execution can be found [here](../key_concepts/poc-diagram.md). However, - it is not fully up-to-date with the implementation discussed here. - -### Known limitations -The `TransactionSettlementSkill` has a known limitation that concerns the revert reason lookup. -While checking the history in `CheckTransactionHistoryRound`, an exception may get raised: - -``` -ValueError: The given transaction has not been reverted! -``` - -This error arises because of the way that we check for the revert reason; We currently -[replay](https://github.com/valory-xyz/open-autonomy/blob/25c9eacae692551eb68aad3977017ca9c5fd337b/packages/valory/contracts/gnosis_safe/contract.py#L614-L619) -the tx locally. However, there is an important limitation with this method. The replayed transaction will be -executed in isolation. This means that transactions which occurred prior to the replayed transaction within -the same block will not be accounted for! Therefore, the replay will not raise a `SolidityError` in such case, -because both the transactions happened in the same block. - -The exception is handled automatically and logged as an error, so it does not affect the execution. -However, as a side effect, we may end the round with a failure status even though the transaction has settled, -because we have not managed to detect it. diff --git a/docs/ethereum_specifics.md b/docs/ethereum_specifics.md deleted file mode 100644 index 72e7c1599d..0000000000 --- a/docs/ethereum_specifics.md +++ /dev/null @@ -1,13 +0,0 @@ -## EIP-1559 Transactions - -With EIP-1559 transaction pricing has changed. Previously, one simply had to set `gasPrice`, now two new pricing parameters have to be set (`maxFeePerGas` and `maxPriorityFeePerGas`): - -- The Base Fee, which is determined by the network itself. And is subsequently burned. (The Base Fee targets 50% full blocks and is based upon the contents of the most recent confirmed block. Depending on how full that new block is, the Base Fee is automatically increased or decreased.) -- A Max Priority Fee, which is optional, determined by the user, and is paid directly to miners. (While the Max Priority Fee is technically optional, at the moment most network participants estimate that transactions generally require a minimum 2.0 GWEI tip to be candidates for inclusion.) -- The Max Fee Per Gas, which is the absolute maximum you are willing to pay per unit of gas to get your transaction included in a block. For brevity and clarity, we will refer to this as the Max Fee. (if the Base Fee plus the Max Priority Fee exceeds the Max Fee (see below), the Max Priority Fee will be reduced in order to maintain the upper bound of the Max Fee. E.g. heuristic: Max Fee = (2 * Base Fee) + Max Priority Fee. Doubling the Base Fee when calculating the Max Fee ensures that your transaction will remain marketable for six consecutive 100% full blocks. ) - -Transactions that include these new fields are known as Type 2, while legacy transactions that carry the original Gas Price field remain supported and known as Type 0. - -EIP-1559 does not bring changes to the Gas Limit, the maximum amount of gas the transaction is authorized to consume. - -Sources: https://notes.ethereum.org/@vbuterin/eip-1559-faq \ No newline at end of file diff --git a/docs/get_started/what_is_an_agent_service.md b/docs/get_started/what_is_an_agent_service.md index 287a692d93..e04690495b 100644 --- a/docs/get_started/what_is_an_agent_service.md +++ b/docs/get_started/what_is_an_agent_service.md @@ -16,17 +16,17 @@ This is what an agent service looks like: ![Architecture of an agent service](../images/agent_service_architecture.svg) -* **Agent service**: The decentralized off-chain service that implements a certain functionality. It is composed of $N$ agents, defined by the owner of the service. +* **Agent service**: The decentralized off-chain service that implements a certain functionality. It is composed of $N$ agents, where $N$ is a parameter that is defined by the owner of the service. -* **Operator**: An entity or individual that owns the infrastructure where an agent is run. Each operator manages an agent instance*and a consensus gadget node. +* **Operator**: An entity or individual that owns the infrastructure where an agent is run. Each operator manages an agent instance and a consensus gadget node. * **Agent**: The software unit that aggregates the runtime and functionalities to execute the service. Each agent is made up of a number of components that implement different functionalities, for example, what communication protocols the agent understands. -* **{{fsm_app}}**: The core component inside an agent that defines a decentralized app implementing the business logic of the service. {{fsm_app}}s implements the underlying mechanisms that allow agents to synchronize their internal state. +* **{{fsm_app}}**: The core component inside an agent that defines the business logic of the service. {{fsm_app}} implements the underlying mechanisms for agents to synchronize their internal state and run the business logic in a decentralized fashion. -* **Consensus gadget:** The infrastructure that enables agents to synchronize the service state and reach consensus on certain important decisions. From a technical point of view, the consensus gadget implements a blockchain based on [Tendermint](https://tendermint.com/). By consensus gadget we usually refer to the collection of consensus nodes + consensus network. +* **Consensus gadget:** The infrastructure that enables agents to synchronize the service state and reach consensus on certain important decisions. From a technical point of view, the consensus gadget implements a blockchain based on [Tendermint](https://tendermint.com/) that is pruned periodically. By consensus gadget we usually refer to the collection of consensus nodes + consensus network. -* **Agent service multisig [Safe](https://safe.global/):** Multisig smart contract that secures the service by requiring a threshold of agents to sign any transaction before it is executed. +* **Agent service multisig [Safe](https://safe.global/):** Smart contract based Multisig that secures the service by requiring a threshold of agents to sign any transaction before it is executed. ## How it works diff --git a/docs/guides/bumping_services.md b/docs/guides/bumping_services.md new file mode 100644 index 0000000000..f7deda3c5a --- /dev/null +++ b/docs/guides/bumping_services.md @@ -0,0 +1,8 @@ +To bump a service to the latest version of open-autonomy follow these steps + +1. Bump open-autonomy and relevant dependencies to the desired version in `tox.ini`, `pipfile/pyproject.toml` and `packages`. You can also use [this](https://github.com/valory-xyz/open-autonomy/blob/main/scripts/bump.py) script to bump the dependencies in your repository. +2. Create a new virtual environment and install the latest dependencies +3. Perform sync and lock the packages + > autonomy packages sync --update-packages --source `valory-xyz/open-autonomy:` --source `valory-xyz/open-aea:` + + > autonomy packages lock diff --git a/docs/guides/code_fsm_app_skill.md b/docs/guides/code_fsm_app_skill.md index 87aa11183f..4f6e67fb94 100644 --- a/docs/guides/code_fsm_app_skill.md +++ b/docs/guides/code_fsm_app_skill.md @@ -1,5 +1,5 @@ -Recall that the [{{fsm_app}} skill](../key_concepts/fsm_app_introduction.md)is the core part of the agent that encodes the business logic of the service. Developing the {{fsm_app}} is possibly most demanding step in the development process. +Recall that the [{{fsm_app}} skill](../key_concepts/fsm_app_introduction.md) is the core part of the agent that encodes the business logic of the service. Developing the {{fsm_app}} is possibly most demanding step in the development process.
![](../images/development_process_code_fsm_app_skill.svg) @@ -36,7 +36,7 @@ You must ensure that your machine satisfies the [framework requirements](./set_u * `rounds.py`, * `payloads.py`. - You should also define a number of test classes. You can review how the [demo services](../demos/index.md) are implemented, or read about the [internals of {{fsm_app}}s](../key_concepts/fsm_app_introduction.md) to learn how to populate the template classes. + You should also define a number of test classes. You can review how the [demo services](https://docs.autonolas.network/demos/) are implemented, or read about the [internals of {{fsm_app}}s](../key_concepts/fsm_app_introduction.md) to learn how to populate the template classes. !!! tip diff --git a/docs/guides/define_agent.md b/docs/guides/define_agent.md index 0dc526ba69..1fc9d39f20 100644 --- a/docs/guides/define_agent.md +++ b/docs/guides/define_agent.md @@ -15,7 +15,7 @@ You must ensure that your machine satisfies the [framework requirements](./set_u ## Step-by-step instructions -In order to deploy and run a service you need an agent with a working {{fsm_app}}. We base this guide in a default {{fsm_app}} available in the remote registry, namely, the `hello_world_abci` {{fsm_app}}. As a result, we will define an agent implementing a functionality equivalent to the [Hello World service](../demos/hello_world_demo.md). You can, of course, use your own {{fsm_app}} to define your agent. +In order to deploy and run a service you need an agent with a working {{fsm_app}}. We base this guide on a default {{fsm_app}} available in the remote registry, namely, the `hello_world_abci` {{fsm_app}}. As a result, we will define an agent implementing a functionality equivalent to the [Hello World service](https://docs.autonolas.network/demos/hello-world/). You can, of course, use your own {{fsm_app}} to define your agent. !!! warning "Important" @@ -46,6 +46,17 @@ If you have [populated the local registry](./set_up.md#populate-the-local-regist * A reference to the {{fsm_app}} skill. * References to other components required by the agent (or dependencies of the {{fsm_app}} skill), under the relevant sections. + + !!! warning "Important" + + There are a number of components which are mandatory for agents that are part of a service: + + * Connections: `valory/abci`. + * Protocols: `open_aea/signing`, `valory/abci`, `valory/acn`(*). + * Skills: `valory/abstract_abci`, `valory/abstract_round_abci`, `valory/termination_abci`(*). + + (*) Components required only if the service is minted in the {{ autonolas_protocol }}. + * Configuration overrides that specify values for component parameters. These overrides are separated by YAML document separators `---` and will be discussed in a further section. ???+ example "Example of an `aea-config.yaml` file" @@ -64,21 +75,21 @@ If you have [populated the local registry](./set_up.md#populate-the-local-regist fingerprint: {} fingerprint_ignore_patterns: [] connections: - - valory/abci:0.1.0:bafybeienpqzsym3rg7nnomd6mxgbt4didwd4wfj72oadde27trdmcgsu5y - - valory/http_client:0.23.0:bafybeidykl4elwbcjkqn32wt5h4h7tlpeqovrcq3c5bcplt6nhpznhgczi - - valory/ipfs:0.1.0:bafybeie46fu7mv64q72dwzoxg77zbiv3pzsigzjk3rehjpm47cf3y77mha - - valory/ledger:0.19.0:bafybeighon6i2qfl2xrg7t3lbdzlkyo4v2a7ayvwso7m5w7pf2hvjfs2ma - - valory/p2p_libp2p_client:0.1.0:bafybeidwcobzb7ut3efegoedad7jfckvt2n6prcmd4g7xnkm6hp6aafrva + - valory/abci:0.1.0 + - valory/http_client:0.23.0 + - valory/ipfs:0.1.0 + - valory/ledger:0.19.0 + - valory/p2p_libp2p_client:0.1.0 contracts: [] protocols: - - open_aea/signing:1.0.0:bafybeibqlfmikg5hk4phzak6gqzhpkt6akckx7xppbp53mvwt6r73h7tk4 - - valory/abci:0.1.0:bafybeig3dj5jhsowlvg3t73kgobf6xn4nka7rkttakdb2gwsg5bp7rt7q4 - - valory/http:1.0.0:bafybeifyoio7nlh5zzyn5yz7krkou56l22to3cwg7gw5v5o3vxwklibhty - - valory/ipfs:0.1.0:bafybeihlgai5pbmkb6mjhvgy4gkql5uvpwvxbpdowczgz4ovxat6vajrq4 + - open_aea/signing:1.0.0 + - valory/abci:0.1.0 + - valory/http:1.0.0 + - valory/ipfs:0.1.0 skills: - - valory/abstract_abci:0.1.0:bafybeigg5ofide2gxwgjvljjgpyy6ombby7ph6pg7erj3h6itduwpn6pqu - - valory/abstract_round_abci:0.1.0:bafybeicn5utwviq46ubguok5rl5go4hb7oxluj7t6bja2ut4epjw2hevei - - valory/hello_world_abci:0.1.0:bafybeigidqcurxh3r3m7vxjfv2d4tvcpzvkhwj7r7owacn6jymzik75k7i + - valory/abstract_abci:0.1.0 + - valory/abstract_round_abci:0.1.0 + - valory/hello_world_abci:0.1.0 default_ledger: ethereum required_ledgers: - ethereum @@ -109,9 +120,9 @@ If you have [populated the local registry](./set_up.md#populate-the-local-regist propagate: true dependencies: open-aea-ledger-ethereum: - version: ==1.32.0 + version: ==1.43.0.post2 open-aea-test-autonomy: - version: ==0.10.2 + version: ==0.12.1.post1 default_connection: null --- public_id: valory/hello_world_abci:0.1.0 @@ -226,7 +237,7 @@ If you have [populated the local registry](./set_up.md#populate-the-local-regist If your agent is using an {{fsm_app}}, you also need to override the variable `all_participants` in the `aea-config.yaml` file with the wallet address of this private key as follows: ```yaml title="aea-config.yaml" - (...) + # (...) all_participants: ${list:["0x15d34AAf54267DB7D7c367839AAf71A00a2C6A65"]} ``` diff --git a/docs/guides/define_service.md b/docs/guides/define_service.md index 35e7ac7bd6..01e8869d95 100644 --- a/docs/guides/define_service.md +++ b/docs/guides/define_service.md @@ -53,7 +53,7 @@ If you have [populated the local registry](./set_up.md#populate-the-local-regist license: Apache-2.0 fingerprint: {} fingerprint_ignore_patterns: [] - agent: valory/hello_world:0.1.0:bafybeictqwn5cqmistwfoq2h3igmytqyfi5jfbei24bofrnhs7deixoily + agent: valory/hello_world:0.1.0 number_of_agents: 4 deployment: {} --- @@ -79,7 +79,7 @@ If you have [populated the local registry](./set_up.md#populate-the-local-regist config: ledger_apis: ethereum: - address: ${SERVICE_HELLO_WORLD_RPC:str:http://host.docker.internal:8545} + address: ${SERVICE_HELLO_WORLD_RPC:str:"http://host.docker.internal:8545"} chain_id: 31337 poa_chain: false default_gas_price_strategy: eip1559 @@ -127,4 +127,4 @@ If you have [populated the local registry](./set_up.md#populate-the-local-regist Service is ready to be deployed. ``` -5. **Use a local deployment to test the service.** This is the recommended approach in order to test your agent service before you publish it to a remote registry. Follow the instructions in the [local deployment guide](./deploy_service.md#local-deployment). Note that this process should be somewhat familiar to you if you have followed the [quick start guide](./quick_start.md). +5. **Use a local deployment to test the service.** This is the recommended approach in order to test your agent service before you publish it to a remote registry. Follow the instructions in the [local deployment guide](./deploy_service.md#local-deployment-full-workflow). Note that this process should be somewhat familiar to you if you have followed the [quick start guide](./quick_start.md). diff --git a/docs/guides/deploy_service.md b/docs/guides/deploy_service.md index d9eb220079..f919f030aa 100644 --- a/docs/guides/deploy_service.md +++ b/docs/guides/deploy_service.md @@ -1,46 +1,61 @@ -Deploying a service with the {{open_autonomy}} framework requires that you have a service configuration file available, which you could be a service created from scratch, fetched from the remote registry, or already registered in the on-chain protocol. +# Deploy the service + +The final step in the development process is [deploying the service](./overview_of_the_development_process.md). There are multiple deployment options to consider, such as deploying on your local machine for testing, deploying on a cluster within your own infrastructure, or deploying on a cloud provider.
![](../images/development_process_deploy_service.svg)
Part of the development process covered in this guide
+The framework supports Docker Compose and Kubernetes cluster deployments. Additionally, the framework automates several steps in the deployment process for services registered in the {{ autonolas_protocol }}. + +!!! tip + + Local service deployments are commonly used for testing services during active development. These deployments allow you to test and validate your service before minting it in the {{ autonolas_protocol }}, ensuring its readiness for production use. + ## What you will learn -This guide covers step 6 of the [development process](./overview_of_the_development_process.md). You will learn how to create and run deployments for local services (testing) and minted services. +This guide covers step 6 of the [development process](./overview_of_the_development_process.md). You will learn the different types of service deployments offered by the framework. You must ensure that your machine satisfies the [framework requirements](./set_up.md#requirements), you have [set up the framework](./set_up.md#set-up-the-framework), and you have a local registry [populated with some default components](./set_up.md#populate-the-local-registry-for-the-guides). As a result you should have a Pipenv workspace folder with an initialized local registry (`./packages`) in it. -## Local deployment +## Local deployment - full workflow -This section covers the deployment of services being developed in the local registry. You can use such deployments to test your service before you mint it in the Autonolas Protocol. +We illustrate the full local deployment workflow using the `hello_world` service as an example, both for Docker Compose and a simple Kubernetes cluster. -1. **Fetch the service.** In the workspace folder, fetch the service from the local registry: - - ```bash - autonomy packages lock - autonomy push-all - autonomy fetch your_name/your_service:0.1.0 --service --local - ``` +1. **Fetch the service.** In the workspace folder, fetch the service from the corresponding registry: - This step is required to have a separate runtime folder (`./your_service`), outside of the local registry. + === "Local registry" + + ```bash + autonomy packages lock + autonomy push-all + autonomy fetch valory/hello_world:0.1.0 --service --local + ``` + + === "Remote registry" + ```bash + autonomy fetch valory/hello_world:0.1.0:bafybeicehljk5ahlsy62t6a5by46uz3nguuxuh653mzoz4hfme22s6eodi --service + ``` -2. **Build the service agents' image.** Navigate to the service folder and build the Docker image of the service agents: +2. **Build the agents' image.** Navigate to the service runtime folder that you have just created and build the Docker image of the agents of the service: ```bash - cd your_service + cd hello_world autonomy build-image #(1)! ``` - - 1. Check out the [`autonomy build-image`](../../advanced_reference/commands/autonomy_build-image) command documentation to learn more about its parameters and options. - After the command finishes building the image, you can see that it has been created by executing: + 1. Check out the [`autonomy build-image`](../../../advanced_reference/commands/autonomy_build-image) command documentation to learn more about its parameters and options. + + After the command finishes, you can check that the image has been created by executing: ```bash - docker image ls | grep + docker image ls | grep ``` -3. **Prepare the keys file.** Prepare a JSON file `keys.json` containing the wallet address and the private key for each of the agents that make up the service. + You can find the `agent_name` within the service configuration file `service.yaml`. + +3. **Prepare the keys file.** Prepare a JSON file `keys.json` containing the wallet address and the private key for each of the agents that you wish to deploy in the local machine. ???+ example "Example of a `keys.json` file" @@ -67,7 +82,7 @@ This section covers the deployment of services being developed in the local regi ] ``` - Export the environment variable `ALL_PARTICIPANTS` with all the agents' addresses: + You also need to export the environment variable `ALL_PARTICIPANTS` with the addresses of **all** the agents in the service. In other words, the addresses of the agents you are deploying (in the `keys.json` file) must be a subset of the addresses in `ALL_PARTICIPANTS`, which might contain additional addresses: ```bash export ALL_PARTICIPANTS='[ @@ -76,89 +91,235 @@ This section covers the deployment of services being developed in the local regi "0x976EA74026E726554dB657fA54763abd0C3a0aa9", "0x14dC79964da2C08b23698B3D3cc7Ca32193d9955" ]' - ``` + ``` +4. **Build the deployment.** Within the service runtime folder, execute the command below to build the service deployment: -4. **Build the deployment.** Within the service folder, execute the command below to build the service deployment. + === "Docker Compose" - ```bash - rm -rf abci_build #(1)! - autonomy deploy build keys.json -ltm #(2)! - ``` + ```bash + rm -rf abci_build #(1)! + autonomy deploy build keys.json -ltm #(2)! + ``` - 1. Delete previous deployments, if necessary. - 2. Check out the [`autonomy deploy build`](../../advanced_reference/commands/autonomy_deploy/#autonomy-deploy-build) command documentation to learn more about its parameters and options. + 1. Delete previous deployments, if necessary. + 2. `-ltm` stands for "use local Tendermint node". Check out the [`autonomy deploy build`](../../../advanced_reference/commands/autonomy_deploy/#autonomy-deploy-build) command documentation to learn more about its parameters and options. + + This will create a deployment environment within the `./abci_build` folder with the following structure: + + ```bash + abci_build/ + ├── agent_keys + │ ├── agent_0 + │ ├── agent_1 + │ | ... + │ └── agent_ + ├── nodes + │ ├── node0 + │ ├── node1 + │ | ... + │ └── node + ├── persistent_data + │ ├── benchmarks + │ ├── logs + │ ├── tm_state + │ └── venvs + └── docker-compose.yaml + ``` - This will create a deployment environment within the `./abci_build` folder with the following structure: + === "Kubernetes" - ```bash - abci_build/ - ├── agent_keys - │ ├── agent_0 - │ ├── agent_1 - │ | ... - │ └── agent_N - ├── nodes - │ ├── node0 - │ ├── node1 - │ | ... - │ └── nodeN - ├── persistent_data - │ ├── benchmarks - │ ├── logs - │ ├── tm_state - │ └── venvs - └── docker-compose.yaml - ``` + ```bash + rm -rf abci_build #(1)! + autonomy deploy build keys.json -ltm --kubernetes #(2)! + ``` -5. **Run the service.** Navigate to the deployment environment folder (`./abci_build`) and run the deployment locally. + 1. Delete previous deployments, if necessary. + 2. `-ltm` stands for "use local Tendermint node". Check out the [`autonomy deploy build`](../../../advanced_reference/commands/autonomy_deploy/#autonomy-deploy-build) command documentation to learn more about its parameters and options. - ```bash - cd abci_build - autonomy deploy run #(1)! - ``` - - 1. Check out the [`autonomy deploy run`](../../advanced_reference/commands/autonomy_deploy/#autonomy-deploy-run) command documentation to learn more about its parameters and options. + This will create a deployment environment within the `./abci_build` folder with the following structure: - This will spawn: - - * $N$ agents, each one running an instance of the {{fsm_app}}. - * a network of $N$ Tendermint nodes, one per agent. + ``` + abci_build/ + ├── agent_keys + │   ├── agent_0_private_key.yaml + │   ├── agent_1_private_key.yaml + │   | ... + │   └── agent__private_key.yaml + ├── build.yaml + └── persistent_data + ├── benchmarks + ├── logs + ├── tm_state + └── venvs + ``` - The logs of a single agent or Tendermint node can be inspected in a separate terminal using `docker logs --follow`. +5. **Execute the deployment.** Navigate to the deployment environment folder (`./abci_build`) and run the deployment locally. - You can cancel the local execution at any time by pressing ++ctrl+c++. + === "Docker Compose" -## On-chain deployment + ```bash + cd abci_build + autonomy deploy run #(1)! + ``` -The {{open_autonomy}} framework provides a convenient interface for [services that are minted](./publish_mint_packages.md). + 1. Check out the [`autonomy deploy run`](../../advanced_reference/commands/autonomy_deploy/#autonomy-deploy-run) command documentation to learn more about its parameters and options. - 1. **Find the service ID.** Explore the [services section](https://protocol.autonolas.network/agents) of the protocol frontend, and note the ID of the service that you want to deploy. The service must be in [Deployed state](https://docs.autonolas.network/protocol/life_cycle_of_a_service/#deployed). + This will spawn in the local machine: - 2. **Execute the service deployment.** Execute the following command + * $N$ agents containers, each one running an instance of the corresponding {{fsm_app}}. + * a network of $N$ Tendermint nodes, one per agent. - ```bash - autonomy deploy from-token keys.json --use-goerli - ``` - where `keys.json` contains the addresses and keys of (some of) the registered agents in the service. - -!!! warning "Important" - When deploying a service registered on-chain, the framework automatically overrides a number of configuration arguments (under `setup`) in the agent containers with the values registered in the on-chain protocol: - - === "skill.yaml" - - ```yaml - (...) - models: - params: - args: - setup: - all_participants: # Overridden with the registered values - safe_contract_address: # Overridden with the registered values - consensus_threshold: # Overridden with the registered values - ``` + === "Kubernetes" + + We show how to run the service deployment using a local [minikube](https://minikube.sigs.k8s.io/docs/start/) cluster. You might want to consider other local cluster options such as [kind](https://kind.sigs.k8s.io/). + + 1. Create the minikube Kubernetes cluster. + ```bash + cd abci_build + minikube start --driver=docker + ``` + + 2. Install chart + + ```bash + helm repo add nfs-ganesha-server-and-external-provisioner https://kubernetes-sigs.github.io/nfs-ganesha-server-and-external-provisioner/ + helm install nfs-provisioner nfs-ganesha-server-and-external-provisioner/nfs-server-provisioner \ + --set=image.tag=v3.0.0,resources.limits.cpu=200m,storageClass.name=nfs-ephemeral -n nfs-local --create-namespace + ``` + + 2. Make sure your image is pushed to Docker Hub (`docker push`). + If this is not the case, you need to provision the cluster with the agent image so that it is available for the cluster pods. + This step might take a while, depending on the size of the image. + ```bash + minikube image load : # (1)! + ``` + + 1. You can get the `` and `` by inspecting the output of `docker image ls`. + + In this case, you also might need to change all the instances of `imagePullPolicy: Always` to `imagePullPolicy: IfNotPresent` in the deployment file `build.yaml`. + + + 3. Define the StorageClass. Replace with your NFS provisioner and adjust per your requirements. We use `minikube-hostpath` as an example. + ```bash + cat < storageclass.yaml + apiVersion: storage.k8s.io/v1 + kind: StorageClass + metadata: + name: nfs-ephemeral + provisioner: kubernetes.io/no-provisioner + volumeBindingMode: WaitForFirstConsumer + reclaimPolicy: Retain + EOF + ``` + + 4. Apply all the deployment files to the cluster + ```bash + kubectl apply --recursive -f . + ``` + + After executing these commands, the minikube cluster will start provisioning and starting $N$ pods in the cluster. Each pod contains: + + * one agent container, running an instance of the corresponding {{fsm_app}}. + * one Tendermint node associated to the agent. + +6. **Examine the deployment.** + + === "Docker Compose" + + To inspect the logs of a single agent or Tendermint node you can execute `docker logs --follow` in a separate terminal. + + You can cancel the local execution at any time by pressing ++ctrl+c++. + + === "Kubernetes" + + You can access the cluster dashboard by executing `minikube dashboard` in a separate terminal. To examine the logs of a single agent or Tendermint node you can execute: + + 1. Get the Kubernetes pod names. + ```bash + kubectl get pod + ``` + + 2. Access the logs of the agent in pod ``. + ```bash + kubectl exec -it -c aea -- /bin/sh + ``` + + 3. Access the logs of the Tendermint node in pod ``. + ```bash + kubectl exec -it -c node0 -- /bin/sh + ``` + + You can delete the local cluster by executing `minikube delete`. + +## Local deployment of minted services + +The framework provides a convenient method to deploy agent services minted in the {{ autonolas_protocol }}. This has the benefit that some configuration parameters of the {{fsm_app}} skill will be overridden automatically with values obtained on-chain. Namely: + +```yaml title="skill.yaml" +# (...) +models: + params: + args: + setup: + all_participants: # Overridden with the registered values in the Autonolas protocol + safe_contract_address: # Overridden with the registered values in the Autonolas protocol + consensus_threshold: # Overridden with the registered values in the Autonolas protocol +``` + +This means, in particular, that there is no need to define the `ALL_PARTICIPANTS` environment variable. + +1. **Find the service ID.** Explore the [services section]({{ autonolas_protocol_registry_dapp_link }}/services) in the {{ autonolas_protocol_registry_dapp }}, and note the token ID of the service that you want to deploy. The service must be in [Deployed state](https://docs.autonolas.network/protocol/life_cycle_of_a_service/#deployed). + +2. **Prepare the keys file.** Prepare a JSON file `keys.json` containing the wallet address and the private key for each of the agents that you wish to deploy in the local machine. + + ???+ example "Example of a `keys.json` file" + + **WARNING: Use this file for testing purposes only. Never use the keys or addresses provided in this example in a production environment or for personal use.** + + ```json title="keys.json" + [ + { + "address": "0x15d34AAf54267DB7D7c367839AAf71A00a2C6A65", + "private_key": "0x47e179ec197488593b187f80a00eb0da91f1b9d0b13f8733639f19c30a34926a" + }, + { + "address": "0x9965507D1a55bcC2695C58ba16FB37d819B0A4dc", + "private_key": "0x8b3a350cf5c34c9194ca85829a2df0ec3153be0318b5e2d3348e872092edffba" + }, + { + "address": "0x976EA74026E726554dB657fA54763abd0C3a0aa9", + "private_key": "0x92db14e403b83dfe3df233f83dfa3a0d7096f21ca9b0d6d6b8d88b2b4ec1564e" + }, + { + "address": "0x14dC79964da2C08b23698B3D3cc7Ca32193d9955", + "private_key": "0x4bbbf85ce3377467afe5d46f804f221813b2bb87f24d81f60f1fcdbf7cbf4356" + } + ] + ``` + +3. **Deploy the service.** Execute the following command: + + === "Docker Compose" + + ```bash + autonomy deploy from-token keys.json --use-goerli # (1)! + ``` + + 1. `--use-goerli` indicates that the service is registered in the Görli testnet. Check out the [`autonomy deploy from-token`](../../../advanced_reference/commands/autonomy_deploy/#autonomy-deploy-from-token) command documentation to learn more about its parameters and options. + + The Docker Compose deployment will be built and run for the agents whose keys are defined in the `keys.json` file. If you just want to build the deployment without running it, simply add the flag `--no-deploy`. + + === "Kubernetes" + + ```bash + autonomy deploy from-token keys.json --use-goerli --kubernetes # (1)! + ``` + + 2. `--use-goerli` indicates that the service is registered in the Görli testnet. Check out the [`autonomy deploy from-token`](../../../advanced_reference/commands/autonomy_deploy/#autonomy-deploy-from-token) command documentation to learn more about its parameters and options. + + The Kubernetes deployment will be built for the agents whose keys are defined in the `keys.json` file. You need to deploy the service in the local cluster manually. Follow the instructions in Step 5 of the [local deployment - full workflow](#local-deployment-full-workflow) section. ## Cloud deployment -!!! info - This section will be added soon. +The sections above for local deployments provide a fundamental understanding of how to deploy agent services in general. The [Open Operator](https://github.com/valory-xyz/open-operator) repository provides the necessary resources and guidelines for seamless cloud deployments of agent services based on the Open Autonomy framework. diff --git a/docs/guides/draft_service_idea_and_define_fsm_specification.md b/docs/guides/draft_service_idea_and_define_fsm_specification.md index 7cb3953125..56bfba1796 100644 --- a/docs/guides/draft_service_idea_and_define_fsm_specification.md +++ b/docs/guides/draft_service_idea_and_define_fsm_specification.md @@ -9,7 +9,7 @@ The first task when designing an agent service is to describe its business logic This guide covers steps 1 and 2 of the [development process](./overview_of_the_development_process.md). You will learn how to write the {{fsm_app}} specification that defines the main steps in the business logic of your service. The actual coding of the {{fsm_app}} will be covered in the next step. -We will use as an example the FSM used in the [Hello World service](../demos/hello_world_demo.md), where a set of 4 agents coordinate and take turns to print a "Hello World" message in their local console. +We will use as an example the FSM used in the [Hello World service](https://docs.autonolas.network/demos/hello-world/), where a set of 4 agents coordinate and take turns to print a "Hello World" message in their local console. You must ensure that your machine satisfies the [framework requirements](./set_up.md#requirements), you have [set up the framework](./set_up.md#set-up-the-framework), and you have a local registry [populated with some default components](./set_up.md#populate-the-local-registry-for-the-guides). As a result you should have a Pipenv workspace folder with an initialized local registry (`./packages`) in it. @@ -22,7 +22,7 @@ Describe the business logic of your service as an FSM. That is, determine, at a * **Transitions** define how to move from one state to another based on the events observed (e.g., if the service observes an error event in a certain state, then move back to the initial state). ???+ example "Example of a service FSM" - This is an example of the FSM of the [Hello World service](../demos/hello_world_demo.md), at high level. You can learn more about the purpose of each of the states, events and transitions in the [dedicated section](../demos/hello_world_demo.md). + This is an example of the FSM of the [Hello World service](https://docs.autonolas.network/demos/hello-world/), at high level. You can learn more about the purpose of each of the states, events and transitions in [its documentation page](https://docs.autonolas.network/demos/hello-world/).
![](../images/hello_world_fsm.svg) @@ -40,7 +40,7 @@ Describe the business logic of your service as an FSM. That is, determine, at a In the workspace folder, create a file `fsm_specification.yaml`, which formally encodes the FSM that you have designed in the previous step. This file must adhere to a syntax that is understood by the framework. Hopefully, the example below is self-explanatory. ???+ example "Example of an `fsm_specification.yaml` file" - Given a draft of the FSM, the structure of the `fsm_specification.yaml` file is quite straightforward. Below we show the FSM specification file of the [Hello World service](../demos/hello_world_demo.md). + Given a draft of the FSM, the structure of the `fsm_specification.yaml` file is quite straightforward. Below we show the FSM specification file of the [Hello World service](https://docs.autonolas.network/demos/hello-world/). ```yaml title="fsm_specification.yaml" alphabet_in: diff --git a/docs/guides/overview_of_the_development_process.md b/docs/guides/overview_of_the_development_process.md index 13a49e3c69..8aa3e4b915 100644 --- a/docs/guides/overview_of_the_development_process.md +++ b/docs/guides/overview_of_the_development_process.md @@ -17,9 +17,9 @@ This is a summary of each step: 5. **Define the service.** This consists in defining the service configuration and declaring what agents constitute the service, together with a number of configuration parameters required. -6. **Publish and mint packages.** Those are required steps to make the service publicly available in the remote registry and secure it in the [Autonolas Protocol](https://docs.autonolas.network/protocol/). +6. **Publish and mint packages.** Those are required steps to make the service publicly available in the remote registry and secure it in the {{ autonolas_protocol }}. -7. **Deploy the service.** You can deploy directly your service locally for testing purposes. To deploy a production service secured in the [Autonolas Protocol](https://docs.autonolas.network/protocol/) you first need to bring the service to the _Deployed_ state in the protocol. +7. **Deploy the service.** You can deploy directly your service locally for testing purposes. To deploy a production service secured in the {{ autonolas_protocol }} you first need to bring the service to the _Deployed_ state in the protocol. In the next sections, we will explore in detail each of these steps in the development process. diff --git a/docs/guides/publish_mint_packages.md b/docs/guides/publish_mint_packages.md index 757ff5b2e7..e91ff23924 100644 --- a/docs/guides/publish_mint_packages.md +++ b/docs/guides/publish_mint_packages.md @@ -1,15 +1,15 @@ -Once you have finished developing and testing your service locally, you can publish your software packages to the remote registry and mint them in the [Autonolas Protocol](https://docs.autonolas.network/protocol/). Minting software packages will produce a representation of them on-chain, in the form of NFTs. +Once you have finished developing and testing your service locally, you can publish your software packages to the remote registry and mint them in the {{ autonolas_protocol }}. Minting software packages will produce a representation of them on-chain, in the form of NFTs.
![](../images/development_process_publish_mint_packages.svg)
Part of the development process covered in this guide
-You can mint packages using the [Autonolas Protocol web app](https://protocol.autonolas.network/) or using the Open Autonomy CLI. +You can mint packages using the {{ autonolas_protocol_registry_dapp }} or using the Open Autonomy CLI. ## What will you learn -This guide covers step 6 of the [development process](./overview_of_the_development_process.md). You will learn how to publish the software packages developed in the local registry (components, agents and services) to the remote registry, and how to mint them in the [Autonolas Protocol](https://docs.autonolas.network/protocol/). +This guide covers step 6 of the [development process](./overview_of_the_development_process.md). You will learn how to publish the software packages developed in the local registry (components, agents and services) to the remote registry, and how to mint them in the {{ autonolas_protocol }}. You must ensure that your machine satisfies the [framework requirements](./set_up.md#requirements), you have [set up the framework](./set_up.md#set-up-the-framework), and you have a local registry [populated with some default components](./set_up.md#populate-the-local-registry-for-the-guides). As a result you should have a Pipenv workspace folder with an initialized local registry (`./packages`) in it. @@ -65,7 +65,7 @@ To mint a software package, all the packages it depends on must be minted first. ### Using the Autonolas Protocol web app -The [Autonolas Protocol web app](https://protocol.autonolas.network/) is a front-end that provides an intuitive GUI to mint components, agents and services, and manage the life cycle of services in the Autonolas Protocol. +The {{ autonolas_protocol_registry_dapp }} is a front-end that provides an intuitive GUI to mint components, agents and services, and manage the life cycle of services in the Autonolas Protocol. We refer to the [Autonolas Protocol docs](https://docs.autonolas.network/protocol/), where you can find instructions on how to mint [components](https://docs.autonolas.network/protocol/mint_packages_nfts/#mint-a-component) (including the {{fsm_app}} skill), [agents](https://docs.autonolas.network/protocol/mint_packages_nfts/#mint-an-agent), and [services](https://docs.autonolas.network/protocol/mint_packages_nfts/#mint-a-service). @@ -108,7 +108,7 @@ Refer to the documentation on the [`autonomy mint` command](../advanced_referenc ### Testing the Autonolas Protocol locally -If you are new to the framework, we provide a way to help you test the [Autonolas Protocol](https://docs.autonolas.network/protocol/) without spending any token on a real chain. +If you are new to the framework, we provide a way to help you test the {{ autonolas_protocol }} without spending any token on a real chain. Namely, we provide a Docker image (`valory/autonolas-registries`) containing a local blockchain (a Hardhat node) with the Autonolas Protocol registry contracts deployed on it. The image also contains a few testing keys and addresses. Below we show the steps to register the `hello_world` service and all its required packages. @@ -125,7 +125,7 @@ Below we show the steps to register the `hello_world` service and all its requir **WARNING: Use these keys for testing purposes only. Never use the keys or addresses provided in this example in a production environment or for personal use.** -2. **Configure your browser and wallet.** To explore the status of the protocol in this local blockchain using the [Autonolas Protocol web app](https://protocol.autonolas.network/), you need to configure a software wallet in your browser, for example [Metamask](https://metamask.io/). Add a new chain with the following parameters: +2. **Configure your browser and wallet.** To explore the status of the protocol in this local blockchain using the {{ autonolas_protocol_registry_dapp }}, you need to configure a software wallet in your browser, for example [Metamask](https://metamask.io/). Add a new chain with the following parameters: * RPC URL: http://localhost:8545 * Chain ID: 31337 @@ -188,7 +188,7 @@ Below we show the steps to register the `hello_world` service and all its requir autonomy mint --use-local service --key minting_key.txt --nft Qmbh9SQLbNRawh9Km3PMEDSxo77k1wib8fYZUdZkhPBiev --owner 0x70997970C51812dc3A010C7d01b50e0d17dc79C8 --agent-id {{ num_minted_agents + 1 }} --number-of-slots 4 --cost-of-bond 10000000000000000 --threshold 3 ./packages/valory/services/hello_world/ ``` -5. **Explore the protocol using the web app.** Use the [Autonolas Protocol web app](https://protocol.autonolas.network/) to explore the packages that you have minted. Ensure that you are connected to the local blockchain configured in Step 2 above through Metamask. +5. **Explore the protocol using the web app.** Use the {{ autonolas_protocol_registry_dapp }} to explore the packages that you have minted. Ensure that you are connected to the local blockchain configured in Step 2 above through Metamask. !!! warning "Important" diff --git a/docs/guides/quick_start.md b/docs/guides/quick_start.md index 56f12c0dea..27f29f37e9 100644 --- a/docs/guides/quick_start.md +++ b/docs/guides/quick_start.md @@ -1,6 +1,6 @@ The purpose of this guide is to provide step-by-step instructions to gain familiarity with the [overall development process](./overview_of_the_development_process.md) of the {{open_autonomy}} framework. -We will show how to use the CLI to run a local deployment of the [Hello World service](../demos/hello_world_demo.md), which comprises: +We will show how to use the CLI to run a local deployment of the [Hello World service](https://docs.autonolas.network/demos/hello-world/), which comprises: - 4 Docker containers implementing the 4 agents of the service, and - 4 Docker containers implementing a Tendermint node for each agent. @@ -17,10 +17,10 @@ Before starting this guide, ensure that your machine satisfies the framework req On **MacOS** and **Windows**, running Docker containers requires having Docker Desktop running as well. If you're using one of those operating systems, remember to start Docker Desktop before you run agent services. -1. Fetch the [Hello World service](../demos/hello_world_demo.md) from the remote registry. Within the workspace folder (not the remote registry) run: +1. Fetch the [Hello World service](https://docs.autonolas.network/demos/hello-world/) from the remote registry. Within the workspace folder (not the remote registry) run: ```bash - autonomy fetch valory/hello_world:0.1.0:bafybeigtaxh5zfg32cypqkjvftreivh22sqlrbgw5x3lxjmrf3dyqcioyy --service + autonomy fetch valory/hello_world:0.1.0:bafybeicehljk5ahlsy62t6a5by46uz3nguuxuh653mzoz4hfme22s6eodi --service ``` 2. Build the Docker image of the service agents: @@ -99,7 +99,7 @@ Before starting this guide, ensure that your machine satisfies the framework req autonomy deploy run ``` - This will deploy the [Hello World service](../demos/hello_world_demo.md) locally with four agents connected to four Tendermint nodes. + This will deploy the [Hello World service](https://docs.autonolas.network/demos/hello-world/) locally with four agents connected to four Tendermint nodes. You can cancel the local execution at any time by pressing ++ctrl+c++. diff --git a/docs/guides/set_up.md b/docs/guides/set_up.md index d2250df843..d9b2f45360 100644 --- a/docs/guides/set_up.md +++ b/docs/guides/set_up.md @@ -4,12 +4,24 @@ The purpose of this guide is to set up your system to work with the {{open_auton Ensure that your machine satisfies the following requirements: -- [Python](https://www.python.org/) `>= 3.7` (recommended `>= 3.10`) +- [Python](https://www.python.org/) `>= 3.8` (recommended `>= 3.10`) - [Pip](https://pip.pypa.io/en/stable/installation/) -- [Pipenv](https://pipenv.pypa.io/en/latest/installation/) `>=2021.x.xx` +- [Pipenv](https://pipenv.pypa.io/en/latest/installation.html) `>=2021.x.xx` - [Docker Engine](https://docs.docker.com/engine/install/) - [Docker Compose](https://docs.docker.com/compose/install/) +Additionally, if you wish to deploy your service in a Kubernetes cluster: + +- [Kubernetes CLI](https://kubernetes.io/docs/tasks/tools/) +- [minikube](https://minikube.sigs.k8s.io/docs/) + + +!!! note + On raspberry-pi currently `Raspberry Pi OS (Legacy, 64-bit, Debian Bullseye)` is tested and supported, The base requirements are same as [above](#requirements). + +!!! tip + Although we will use these tools for demonstration purposes only, you might as well consider other local Kubernetes cluster options like [kind](https://kind.sigs.k8s.io/docs/user/quick-start/), or even additional tools like [Skaffold](https://skaffold.dev/) or [Helm](https://helm.sh/) to help you with your cluster deployments. + ## Set up the framework 1. **Create a workspace folder:** @@ -67,7 +79,7 @@ This is roughly how your workspace should look like: You can override the default registry in use (set up with `autonomy init`) for a particular command through the flags `--registry-path` and `--local`. For example, if the framework was initialized with the remote registry, the following command will fetch a runtime folder for the `hello_world` agent from the remote registry: ```bash - autonomy fetch valory/hello_world:0.1.0:bafybeidghah5yexnsdxwplnbyq3u3bgl2mmjur2eef4bxenf6ddb3zs2ca + autonomy fetch valory/hello_world:0.1.0:bafybeib5grnum25svkpozqqnvpd7nmwoaypnc3l7lbnoj335nwgczsiyca ``` On the other hand, if you want to fetch the copy stored in your local registry, then you can use: @@ -98,25 +110,25 @@ If you plan to follow the guides in the next sections, you need to populate the "dev": { }, "third_party": { - "service/valory/hello_world/0.1.0": "bafybeigtaxh5zfg32cypqkjvftreivh22sqlrbgw5x3lxjmrf3dyqcioyy", - "agent/valory/hello_world/0.1.0": "bafybeidghah5yexnsdxwplnbyq3u3bgl2mmjur2eef4bxenf6ddb3zs2ca", - "connection/valory/abci/0.1.0": "bafybeih2l6ssf5ebkvgbag3hx2pd22shytszqavveib2e2s6rv4va5khv4", - "connection/valory/http_client/0.23.0": "bafybeidykl4elwbcjkqn32wt5h4h7tlpeqovrcq3c5bcplt6nhpznhgczi", - "connection/valory/ipfs/0.1.0": "bafybeihubpyw2t3bwncz3l7jt4gf5xvfydwmob463vvgf3ikkhlwxakm3m", - "connection/valory/ledger/0.19.0": "bafybeicgfupeudtmvehbwziqfxiz6ztsxr5rxzvalzvsdsspzz73o5fzfi", - "contract/valory/service_registry/0.1.0": "bafybeiatzikdgcjteti6xeid4bvofszuavxb4fnczx33lcsvlaui4wpwua", - "protocol/open_aea/signing/1.0.0": "bafybeibqlfmikg5hk4phzak6gqzhpkt6akckx7xppbp53mvwt6r73h7tk4", - "protocol/valory/abci/0.1.0": "bafybeig3dj5jhsowlvg3t73kgobf6xn4nka7rkttakdb2gwsg5bp7rt7q4", - "protocol/valory/acn/1.1.0": "bafybeignmc5uh3vgpuckljcj2tgg7hdqyytkm6m5b6v6mxtazdcvubibva", - "protocol/valory/contract_api/1.0.0": "bafybeidv6wxpjyb2sdyibnmmum45et4zcla6tl63bnol6ztyoqvpl4spmy", - "protocol/valory/http/1.0.0": "bafybeifyoio7nlh5zzyn5yz7krkou56l22to3cwg7gw5v5o3vxwklibhty", - "protocol/valory/ipfs/0.1.0": "bafybeic72ncgqbzoz2guj4p4yjqulid7mv6yroeh65hxznloamoveeg7hq", - "protocol/valory/ledger_api/1.0.0": "bafybeibo4bdtcrxi2suyzldwoetjar6pqfzm6vt5xal22ravkkcvdmtksi", - "protocol/valory/tendermint/0.1.0": "bafybeicusvezoqlmyt6iqomcbwaz3xkhk2qf3d56q5zprmj3xdxfy64k54", - "agent/valory/abstract_abci/0.1.0": "bafybeibqmgh6v5bfe7covmznjirpaf4r2cw4x7rqmt6toxhqjmuzpan7he", - "skill/valory/abstract_round_abci/0.1.0": "bafybeigiolzp3i6b3wwuau3yv2h5udqape3i7of73mlm2d6ud22irlkbme", - "skill/valory/hello_world_abci/0.1.0": "bafybeiccrdfvkbrwawroglielcn2pf6vhhz7hoba2ya46ryd5zpmk4al5u", - "connection/valory/p2p_libp2p_client/0.1.0": "bafybeidwcobzb7ut3efegoedad7jfckvt2n6prcmd4g7xnkm6hp6aafrva" + "service/valory/hello_world/0.1.0": "bafybeicehljk5ahlsy62t6a5by46uz3nguuxuh653mzoz4hfme22s6eodi", + "agent/valory/hello_world/0.1.0": "bafybeib5grnum25svkpozqqnvpd7nmwoaypnc3l7lbnoj335nwgczsiyca", + "connection/valory/abci/0.1.0": "bafybeih4lb2myvtypnfeji5jmgikmmazpgl3vyf5sy7oe66ji2zfjj6ily", + "connection/valory/http_client/0.23.0": "bafybeiddrfvomrmgvh5yuv2coq7ci72wcdf663stayi3m5aawnj4srggce", + "connection/valory/ipfs/0.1.0": "bafybeigjtca6b5wwiobl37es3wllzt6ai3qef5gqxzfy5fmmc65jkbnec4", + "connection/valory/ledger/0.19.0": "bafybeia47rr37ianvwsh77tjjpv3nwif5sywhhy2fbdshnz4a2icwln76a", + "contract/valory/service_registry/0.1.0": "bafybeieeuruq7dp4b6souetv5ce7wlm52pw7vyrxuhqa7kuy5m3rwwxks4", + "protocol/open_aea/signing/1.0.0": "bafybeie7xyems76v5b4wc2lmaidcujizpxfzjnnwdeokmhje53g7ym25ii", + "protocol/valory/abci/0.1.0": "bafybeihmzlmmb4pdo3zkhg6ehuyaa4lhw7bfpclln2o2z7v3o6fcep26iu", + "protocol/valory/acn/1.1.0": "bafybeic2pxzfc3voxl2ejhcqyf2ehm4wm5gxvgx7bliloiqi2uppmq6weu", + "protocol/valory/contract_api/1.0.0": "bafybeialhbjvwiwcnqq3ysxcyemobcbie7xza66gaofcvla5njezkvhcka", + "protocol/valory/http/1.0.0": "bafybeiejoqgv7finfxo3rcvvovrlj5ccrbgxodjq43uo26ylpowsa3llfe", + "protocol/valory/ipfs/0.1.0": "bafybeiedxeismnx3k5ty4mvvhlqideixlhqmi5mtcki4lxqfa7uqh7p33u", + "protocol/valory/ledger_api/1.0.0": "bafybeige5agrztgzfevyglf7mb4o7pzfttmq4f6zi765y4g2zvftbyowru", + "protocol/valory/tendermint/0.1.0": "bafybeig6g6twajlwssfbfp5rlnu5mwzuu5kgak5cs4fich7rlkx6whesnu", + "skill/valory/abstract_abci/0.1.0": "bafybeial6drwstqlvuizgtouc4uqgxvutwryfu7yohondemd6bd7cw3jzm", + "skill/valory/abstract_round_abci/0.1.0": "bafybeicrzndcdbue34yxwwb4hmmdhgzw4owcdcdag3ifj6thpx5wie3dp4", + "skill/valory/hello_world_abci/0.1.0": "bafybeiabaamrsmq3ysbdk4gxym7in5urwyyfmegto3v5hgqc6etn7g6ubi", + "connection/valory/p2p_libp2p_client/0.1.0": "bafybeihge56dn3xep2dzomu7rtvbgo4uc2qqh7ljl3fubqdi2lq44gs5lq" } } ``` diff --git a/docs/images/favicon.ico b/docs/images/favicon.ico new file mode 100644 index 0000000000..19ffc789d3 Binary files /dev/null and b/docs/images/favicon.ico differ diff --git a/docs/images/favicon16x16.png b/docs/images/favicon16x16.png new file mode 100644 index 0000000000..7e0179306b Binary files /dev/null and b/docs/images/favicon16x16.png differ diff --git a/docs/images/favicon32x32.png b/docs/images/favicon32x32.png new file mode 100644 index 0000000000..6a9d62041c Binary files /dev/null and b/docs/images/favicon32x32.png differ diff --git a/docs/images/favicon96x96.png b/docs/images/favicon96x96.png new file mode 100644 index 0000000000..1fe0267e59 Binary files /dev/null and b/docs/images/favicon96x96.png differ diff --git a/docs/images/hello_world_action.svg b/docs/images/hello_world_action.svg deleted file mode 100644 index 489f0e13ac..0000000000 --- a/docs/images/hello_world_action.svg +++ /dev/null @@ -1,3 +0,0 @@ - - -
Hello World Agent Service
Hello World Agent Service
Agent 3 says:
Hello World!
Agent 3 says:...
Hello World Agent Service
Hello World Agent Service
Agent 1 says:
Hello World!
Agent 1 says:...
Period 1
Period 1
Period 2
Period 2
Hello World Agent Service
Hello World Agent Service
Agent 2 says:
Hello World!
Agent 2 says:...
Period 3
Period 3
Consensus gadget
Consensus gadget
Agent 1
Agent 1
Agent 2
Agent 2
Agent 4
Agent 4
Agent 3
Agent 3
Consensus gadget
Consensus gadget
Agent 1
Agent 1
Agent 2
Agent 2
Agent 4
Agent 4
Agent 3
Agent 3
Consensus gadget
Consensus gadget
Agent 1
Agent 1
Agent 2
Agent 2
Agent 4
Agent 4
Agent 3
Agent 3
Time
Time
Text is not SVG - cannot display
\ No newline at end of file diff --git a/docs/images/hello_world_agent_internal.svg b/docs/images/hello_world_agent_internal.svg deleted file mode 100644 index a432691820..0000000000 --- a/docs/images/hello_world_agent_internal.svg +++ /dev/null @@ -1,3 +0,0 @@ - - -
Consensus gadget
Consensus gadget
Agent
Agent
Hello World FSM App Skill
Hello World FSM App Skill
RoundBehaviour
RoundBehaviour
AbciApp
AbciApp
SelectKeeperBehaviour
SelectKeeperBehaviour
RegistrationBehaviour
RegistrationBehaviour
PrintMessageBehaviour
PrintMessageBehaviour
ResetAndPauseBehaviour
ResetAndPauseBehaviour
other_skill_1
other_skill_1
AbciRoundHandler
AbciRoundHandler
ABCI
ABCI
other_component_1
other_component_1
other_component_2
other_component_2
other_component_3
other_component_3
other_skill_2
other_skill_2
other_skill_3
other_skill_3
Consensus gadget node
Consensus gadget node
Consensus gadget network
Consensus gadget...
Other consensus
gadget node
Other consensus...
Other consensus
gadget  node
Other consensus...
Other consensus
gadget node
Other consensus...
ResetAndPause
ResetAndPause
SelectKeeper
SelectKeeper
PrintMessage
PrintMessage
Registration
Registration
DONE
DONE
DONE
DONE
DONE
DONE
CollectRandomness
CollectRandomness
DONE
DONE
DONE
DONE
CollectRandomnessBehaviour
CollectRandomnessBehaviour
Text is not SVG - cannot display
\ No newline at end of file diff --git a/docs/images/hello_world_demo_architecture_simplified.svg b/docs/images/hello_world_demo_architecture_simplified.svg deleted file mode 100644 index 37eb6643af..0000000000 --- a/docs/images/hello_world_demo_architecture_simplified.svg +++ /dev/null @@ -1,3 +0,0 @@ - - -
Hello World Agent Service
Hello World Agent Service
Consensus gadget
Consensus gadget
Agent 1
Agent 1
Agent 2
Agent 2
Agent 4
Agent 4
Agent 3
Agent 3
Text is not SVG - cannot display
\ No newline at end of file diff --git a/docs/images/hello_world_result.svg b/docs/images/hello_world_result.svg deleted file mode 100644 index 3301188471..0000000000 --- a/docs/images/hello_world_result.svg +++ /dev/null @@ -1,3 +0,0 @@ - - -
Hello World Agent Service
Hello World Agent Service
Agent 2 says:
Hello World!
Agent 2 says:...
Consensus gadget
Consensus gadget
Agent 1
Agent 1
Agent 2
Agent 2
Agent 4
Agent 4
Agent 3
Agent 3
Text is not SVG - cannot display
\ No newline at end of file diff --git a/docs/images/hello_world_sequence_1.svg b/docs/images/hello_world_sequence_1.svg deleted file mode 100644 index 17243e2719..0000000000 --- a/docs/images/hello_world_sequence_1.svg +++ /dev/null @@ -1,3 +0,0 @@ - - -
Hello World Agent Service
Hello World Agent Service
Consensus gadget
Consensus gadget
Agent 1
Agent 1
Agent 2
Agent 2
Agent 4
Agent 4
Agent 3
Agent 3
"I vote for Agent 2"
"I vote for...
"I vote for Agent 2"
"I vote for...
"I vote for Agent 2"
"I vote for...
Agent 2
Agent 2
Hello World FSM App Skill
Hello World FSM App Skill
other_skill_1
other_skill_1
other_skill_2
other_skill_2
other_skill_3
other_skill_3
SelectKeeper Behaviour
SelectKeeper Behavio...
"I vote for Agent 2"
"I vote for...
Text is not SVG - cannot display
\ No newline at end of file diff --git a/docs/images/hello_world_sequence_2.svg b/docs/images/hello_world_sequence_2.svg deleted file mode 100644 index 4c7048113a..0000000000 --- a/docs/images/hello_world_sequence_2.svg +++ /dev/null @@ -1,3 +0,0 @@ - - -
Hello World Agent Service
Hello World Agent Service
Consensus gadget
Consensus gadget
Agent 1
Agent 1
Agent 2
Agent 2
Agent 4
Agent 4
Agent 3
Agent 3
2
2
Agent 2
Agent 2
Hello World FSM App Skill
Hello World FSM App Skill
other_skill_1
other_skill_1
other_skill_2
other_skill_2
other_skill_3
other_skill_3
"I vote for Agent 2"
"I vote for...
2
2
2
2
2
2
SelectKeeper Behaviour
SelectKeeper Behavio...
Text is not SVG - cannot display
\ No newline at end of file diff --git a/docs/images/hello_world_sequence_3.svg b/docs/images/hello_world_sequence_3.svg deleted file mode 100644 index 199325a59f..0000000000 --- a/docs/images/hello_world_sequence_3.svg +++ /dev/null @@ -1,3 +0,0 @@ - - -
Hello World Agent Service
Hello World Agent Service
Consensus gadget
Consensus gadget
Agent 1
Agent 1
Agent 2
Agent 2
Agent 4
Agent 4
Agent 3
Agent 3
Ensures that all the agents have the same consistent view:
Ensures that all the agents ha...
Agent 1  2  3  4 
Voted for2222
Agent 1  2  3  4 Voted f...
Text is not SVG - cannot display
\ No newline at end of file diff --git a/docs/images/hello_world_sequence_4.svg b/docs/images/hello_world_sequence_4.svg deleted file mode 100644 index 2032e2a30a..0000000000 --- a/docs/images/hello_world_sequence_4.svg +++ /dev/null @@ -1,3 +0,0 @@ - - -
Hello World Agent Service
Hello World Agent Service
Consensus gadget
Consensus gadget
Agent 1
Agent 1
Agent 2
Agent 2
Agent 4
Agent 4
Agent 3
Agent 3
Agent 2
Agent 2
Hello World FSM App Skill
Hello World FSM App Skill
other_skill_1
other_skill_1
other_skill_2
other_skill_2
other_skill_3
other_skill_3
Text is not SVG - cannot display
\ No newline at end of file diff --git a/docs/images/hello_world_sequence_5.svg b/docs/images/hello_world_sequence_5.svg deleted file mode 100644 index 901047d9c2..0000000000 --- a/docs/images/hello_world_sequence_5.svg +++ /dev/null @@ -1,3 +0,0 @@ - - -
Hello World Agent Service
Hello World Agent Service
Consensus gadget
Consensus gadget
Agent 1
Agent 1
Agent 2
Agent 2
Agent 4
Agent 4
Agent 3
Agent 3
Agent 2
Agent 2
Hello World FSM App Skill
Hello World FSM App Skill
other_skill_1
other_skill_1
other_skill_2
other_skill_2
other_skill_3
other_skill_3
Text is not SVG - cannot display
\ No newline at end of file diff --git a/docs/images/hello_world_zoom_agent.svg b/docs/images/hello_world_zoom_agent.svg deleted file mode 100644 index c77f9aa805..0000000000 --- a/docs/images/hello_world_zoom_agent.svg +++ /dev/null @@ -1,3 +0,0 @@ - - -
Hello World Agent Service
Hello World Agent Service
Consensus gadget
Consensus gadget
Agent 1
Agent 1
Agent 2
Agent 2
Agent 4
Agent 4
Agent 3
Agent 3
Agent 2
Agent 2
Hello World FSM App Skill
Hello World FSM App Skill
other_skill_1
other_skill_1
other_skill_2
other_skill_2
other_skill_3
other_skill_3
Text is not SVG - cannot display
\ No newline at end of file diff --git a/docs/images/logo.svg b/docs/images/logo.svg new file mode 100644 index 0000000000..9f296cf772 --- /dev/null +++ b/docs/images/logo.svg @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + diff --git a/docs/images/logo_purple.svg b/docs/images/logo_purple.svg new file mode 100644 index 0000000000..e38f84aa1e --- /dev/null +++ b/docs/images/logo_purple.svg @@ -0,0 +1,77 @@ + + + + + + + + + + + + + + + + + diff --git a/docs/images/oracle_composition.svg b/docs/images/oracle_composition.svg deleted file mode 100644 index ce2b7921e3..0000000000 --- a/docs/images/oracle_composition.svg +++ /dev/null @@ -1,3 +0,0 @@ - - -
Oracle AbciApp
Oracle AbciApp
Agent Registration
AbciApp
Agent Registrat...
Safe Deployment
AbciApp
Safe Deployment...
Oracle Deployment
AbciApp
Oracle Deployme...
Transaction Submission
AbciApp
Transaction Sub...
Price Aggregation
AbciApp
Price Aggregati...
Reset Pause AbciApp
Reset Pause Abc...
Normal path
Normal path
Errors and failures
Errors and failures
Text is not SVG - cannot display
\ No newline at end of file diff --git a/docs/images/oracle_diagram.svg b/docs/images/oracle_diagram.svg deleted file mode 100644 index 3695f6a5c1..0000000000 --- a/docs/images/oracle_diagram.svg +++ /dev/null @@ -1,3 +0,0 @@ - - -
Oracle Agent Service
Oracle Agent Service
Operator 1
Operator 1
Operator 2
Operator 2
Operator 3
Operator 3
Operator 4
Operator 4
Agent 1
Agent 1
Oracle FSM App
Oracle FSM App
Agent 2
Agent 2
Oracle FSM App
Oracle FSM App
Agent 3
Agent 3
Oracle FSM App
Oracle FSM App
Consensus gadget node
Consensus gad...
Consensus gadget node
Consensus gad...
Consensus gadget node
Consensus gad...
Consensus gadget network
Consensus gadget ne...
Agent 4
Agent 4
Oracle FSM App
Oracle FSM App
Consensus gadget node
Consensus gad...
BTC data provider 4
BTC data p...
BTC data provider 1
BTC data p...
BTC data provider 2
BTC data p...
BTC data provider 3
BTC data p...
Internet
Internet
Local blockchain network
Local blockchain ne...
Text is not SVG - cannot display
\ No newline at end of file diff --git a/docs/index.md b/docs/index.md index 899edce820..858b1a2413 100644 --- a/docs/index.md +++ b/docs/index.md @@ -18,7 +18,7 @@ The framework provides: !!! abstract "Read the Whitepaper" - The [Autonolas Whitepaper](https://autonolas.network/whitepaper/autonolas-whitepaper.pdf), presents a comprehensive discussion on the architecture of the Autonolas Ecosystem. The Open Autonomy framework connects with the **Technical Architecture** section therein as a facilitator to build autonomous services. + The {{ autonolas_whitepaper }}, presents a comprehensive discussion on the architecture of the Autonolas stack. The Open Autonomy framework connects with the **Technical Architecture** section therein as a facilitator to build autonomous services. ## Building with Open Autonomy @@ -44,13 +44,6 @@ Follow the guides to learn how to use the framework to **create and deploy agent ------ -A tour to **existing agent services** that you can explore and use them as a reference -for your implementations. - -[Demos](./demos/index.md){ .md-button } - ------- - Detailed topics on how the **internal components** of an agent service work with the framework. @@ -58,12 +51,12 @@ framework. ------ -Browse through the CLI and API reference documentation. +Browse through the CLI and API **reference documentation**. [Advanced reference](./advanced_reference/index.md){ .md-button } ------ -Browse our FAQ where you can find commonly asked questions about the framework. +Browse our FAQ where you can find **commonly asked questions** about the framework. [FAQ](./questions-and-answers.md){ .md-button } diff --git a/docs/key_concepts/abci_app_abstract_round_behaviour.md b/docs/key_concepts/abci_app_abstract_round_behaviour.md index c8b5d5396e..8672dd4a35 100644 --- a/docs/key_concepts/abci_app_abstract_round_behaviour.md +++ b/docs/key_concepts/abci_app_abstract_round_behaviour.md @@ -36,7 +36,7 @@ class AbstractRoundBehaviour( def act(self) -> None: """Implement the behaviour.""" self._process_current_round() - # ... + # (...) ``` A concrete implementation of `AbstractRoundBehaviour` requires that the developer provide the corresponding @@ -63,5 +63,5 @@ class MyAbstractRoundBehaviour(AbstractRoundBehaviour): RoundB, FinalRound, } - # ... + # (...) ``` diff --git a/docs/key_concepts/abci_app_async_behaviour.md b/docs/key_concepts/abci_app_async_behaviour.md index 12d27bcc41..9db5490366 100644 --- a/docs/key_concepts/abci_app_async_behaviour.md +++ b/docs/key_concepts/abci_app_async_behaviour.md @@ -74,7 +74,7 @@ class SimpleBehaviour(Behaviour, ABC): def act(self) -> None: """Do the action.""" - # ... + # (...) ``` The `AsyncBehaviour` utility class allows to wrap the execution @@ -102,7 +102,7 @@ class AsyncBehaviour(ABC): @abstractmethod def async_act_wrapper(self) -> Generator: """Do the act, supporting asynchronous execution.""" - # ... + # (...) ``` The abstract methods the developer should implement are called @@ -214,7 +214,7 @@ As explained above, one of the common tasks for a behaviour is to interact with other services and/or agents via message-based communication. In this section, we focus on a sequence of request-response interactions through agent interaction protocols. -We consider the `fetchai/generic_buyer` skill as an example ([link to code](https://github.com/valory-xyz/open-aea/tree/v1.32.0/packages/fetchai/skills/generic_buyer)). +We consider the `fetchai/generic_buyer` skill as an example ([link to code](https://github.com/valory-xyz/open-aea/tree/v1.37.0/packages/fetchai/skills/generic_buyer)). ### The idiomatic approach @@ -321,7 +321,7 @@ class GenericBuyerBehaviour(OneShotBehaviour, AsyncBehaviour): # here there should be the buyer strategy # for the negotiation with the seller... - # ... + # (...) # in case both parties accept the negotiation outcome: tx = build_tx(...) diff --git a/docs/key_concepts/abci_app_class.md b/docs/key_concepts/abci_app_class.md index b764e44ea4..cea30395d5 100644 --- a/docs/key_concepts/abci_app_class.md +++ b/docs/key_concepts/abci_app_class.md @@ -40,15 +40,16 @@ class AbciApp( ): """Initialize the AbciApp.""" - def process_transaction(self, transaction: Transaction) -> None: + def process_transaction(self, transaction: Transaction, dry: bool = False) -> None: """ Process a transaction. - The background round runs concurrently with other (normal) rounds. - First we check if the transaction is meant for the background round, - if not we forward to the current round object. + The background rounds run concurrently with other (normal) rounds. + First we check if the transaction is meant for a background round, + if not we forward it to the current round object. :param transaction: the transaction. + :param dry: whether the transaction should only be checked and not processed. """ def process_event( @@ -62,7 +63,7 @@ class AbciApp( :param timestamp: the latest block's timestamp. """ - # ... + # (...) ``` Some of its methods relate to concepts discussed in the [FSM section](./fsm.md): @@ -112,7 +113,7 @@ class MyAbciApp(AbciApp): get_name(BaseSynchronizedData.generated_value), }, } - # ... + # (...) ```
diff --git a/docs/package_list.md b/docs/package_list.md index cb56494163..d183504dfe 100644 --- a/docs/package_list.md +++ b/docs/package_list.md @@ -1,51 +1,54 @@ | Package name | Package hash | Description | | ------------------------------------------------------------- | ------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------- | -| protocol/valory/abci/0.1.0 | `bafybeig3dj5jhsowlvg3t73kgobf6xn4nka7rkttakdb2gwsg5bp7rt7q4` | A protocol for ABCI requests and responses. | -| connection/valory/abci/0.1.0 | `bafybeih2l6ssf5ebkvgbag3hx2pd22shytszqavveib2e2s6rv4va5khv4` | connection to wrap communication with an ABCI server. | -| connection/valory/ipfs/0.1.0 | `bafybeihubpyw2t3bwncz3l7jt4gf5xvfydwmob463vvgf3ikkhlwxakm3m` | A connection responsible for uploading and downloading files from IPFS. | -| contract/valory/gnosis_safe_proxy_factory/0.1.0 | `bafybeierle6peb4a5cw3tncgondwhgesomzg7tedkb5cuos2zm462asbdi` | Gnosis Safe proxy factory (GnosisSafeProxyFactory) contract | -| contract/valory/component_registry/0.1.0 | `bafybeifeujuzp56zzdhyvxitnaakqetcqhbqr2x6jxnhj7ahzm7pb2y7uy` | Component registry contract | -| contract/valory/agent_registry/0.1.0 | `bafybeifdrul5qvk5hj4ggy63ff3smt6wc4c67srnqxxfpbz3jsgbpuavgy` | Agent registry contract | -| contract/valory/registries_manager/0.1.0 | `bafybeibnvf4z2oi344lsrxcfav3q3udlzokdfa62yc5oui2nuxwupezu7u` | Registries Manager contract | -| contract/valory/service_manager/0.1.0 | `bafybeihvogcziooqau7n22tejzan2baghjaodkb2u74i3aao7ffomk4aem` | Service Manager contract | -| skill/valory/test_ipfs_abci/0.1.0 | `bafybeic7ma7ipbzqno5hvv25aif6rqvmi7gb6vj2kpjbph7jrzidehxose` | IPFS e2e testing application. | -| agent/valory/test_ipfs/0.1.0 | `bafybeiedrr6izfvibnwkedsx2v3nmcd5jwomk5k7xralk6nbumiqvznaou` | Agent for testing the ABCI connection. | -| contract/valory/service_registry/0.1.0 | `bafybeiatzikdgcjteti6xeid4bvofszuavxb4fnczx33lcsvlaui4wpwua` | Service Registry contract | -| protocol/valory/tendermint/0.1.0 | `bafybeicusvezoqlmyt6iqomcbwaz3xkhk2qf3d56q5zprmj3xdxfy64k54` | A protocol for communication between two AEAs to share tendermint configuration details. | -| protocol/valory/ipfs/0.1.0 | `bafybeic72ncgqbzoz2guj4p4yjqulid7mv6yroeh65hxznloamoveeg7hq` | A protocol specification for IPFS requests and responses. | -| skill/valory/abstract_abci/0.1.0 | `bafybeifuclb6cikagtg2zn7dkjnnv3f7re2tfgzk6c4h3scgyzaaqeg55m` | The abci skill provides a template of an ABCI application. | -| contract/valory/gnosis_safe/0.1.0 | `bafybeifvqalsuyetul3ypuolxvxzi5ffxoqdbqpfl3jadqjachsw7qfs74` | Gnosis Safe (GnosisSafeL2) contract | -| skill/valory/abstract_round_abci/0.1.0 | `bafybeigiolzp3i6b3wwuau3yv2h5udqape3i7of73mlm2d6ud22irlkbme` | abstract round-based ABCI application | -| contract/valory/multisend/0.1.0 | `bafybeigjywkl7hydjsrkogob3xebj2ifhqwmfhhxoeyrndzhhxi5u6amey` | MultiSend contract | -| skill/valory/transaction_settlement_abci/0.1.0 | `bafybeifsz2ll7gmy6vmx34t6q5bdv6zzwp5zrehr6di6v3thcpc3sztkta` | ABCI application for transaction settlement. | -| skill/valory/registration_abci/0.1.0 | `bafybeigjzfdhhu6ody2qo5v2xjobafujnodklia4zw6bkkhahxtjfo3wby` | ABCI application for common apps. | -| skill/valory/reset_pause_abci/0.1.0 | `bafybeieeux3rdlcwgjbdfrluvkhqv26qdparre6pabatietw7juklljil4` | ABCI application for resetting and pausing app executions. | -| skill/valory/termination_abci/0.1.0 | `bafybeifkl4ab6dnvtsaefe56dbzshmp5mozn7exwcaj2a3wjeq7u3hpezm` | Termination skill. | -| skill/valory/counter/0.1.0 | `bafybeicodfeaolvkppkfoergy4vr5rc5nwntvadr2iebqjklawkvtfea2u` | The ABCI Counter application example. | -| skill/valory/counter_client/0.1.0 | `bafybeiaqdfulxamdshw7fykfkqvkpvjb5bnmhv7ffrjiwdi4ktiulklx6q` | A client for the ABCI counter application. | -| skill/valory/hello_world_abci/0.1.0 | `bafybeiccrdfvkbrwawroglielcn2pf6vhhz7hoba2ya46ryd5zpmk4al5u` | Hello World ABCI application. | -| skill/valory/register_reset_abci/0.1.0 | `bafybeigvyiefdckrxjz67nxwswj73y7dbpj674bca4zd27gdcs6lcy2fku` | ABCI application for dummy skill that registers and resets | -| skill/valory/register_termination_abci/0.1.0 | `bafybeidv74qpb5k6p5l3fn7qf4bo5o44dx6xfyj2i53rkazq6veyzeos5e` | ABCI application for dummy skill that registers and resets | -| skill/valory/test_abci/0.1.0 | `bafybeifbskwxg3vz6rl4vcgn4vdeyi5eqxewfnxv4o6ugeyilibmmimbn4` | ABCI application for testing the ABCI connection. | -| agent/valory/abstract_abci/0.1.0 | `bafybeibqmgh6v5bfe7covmznjirpaf4r2cw4x7rqmt6toxhqjmuzpan7he` | The abstract ABCI AEA - for testing purposes only. | -| agent/valory/counter/0.1.0 | `bafybeigkxgd644pzmfigkcprpvv7fkchoj6syyfymvdpeiobpqawfdeq5i` | The ABCI Counter example as an AEA | -| agent/valory/counter_client/0.1.0 | `bafybeigp4ayq6lsjdeu4pltrksqwcd5lnoqpuhtwznzc5w5y75337ptfo4` | The ABCI Counter example as an AEA | -| agent/valory/hello_world/0.1.0 | `bafybeidghah5yexnsdxwplnbyq3u3bgl2mmjur2eef4bxenf6ddb3zs2ca` | Hello World ABCI example. | -| agent/valory/register_reset/0.1.0 | `bafybeibs3dm6jixfv2m2k67mjduokbxdnod6esjo337tcoa7cudnspr76m` | Register reset to replicate Tendermint issue. | -| agent/valory/register_termination/0.1.0 | `bafybeiatofnu3hipdhdiwzhabv3juqhockz5lvvltb6qkzl5ylmpgb66pq` | Register terminate to test the termination feature. | -| agent/valory/registration_start_up/0.1.0 | `bafybeifozuszux33n6wtq3urdaqeadzeeobcn4dnddevenri2cgph6k6lm` | Registration start-up ABCI example. | -| agent/valory/test_abci/0.1.0 | `bafybeidjoxttpyoqrdsnmepytxsksm6xcyioancu4yoccuxadul4znd3ry` | Agent for testing the ABCI connection. | -| service/valory/counter/0.1.0 | `bafybeihzpb3uz7gdclswkusnsbsjgnnmh7xbkwbulkxzpgjteqhfsynvzy` | A set of agents incrementing a counter | -| service/valory/hello_world/0.1.0 | `bafybeigtaxh5zfg32cypqkjvftreivh22sqlrbgw5x3lxjmrf3dyqcioyy` | A simple demonstration of a simple ABCI application | -| service/valory/register_reset/0.1.0 | `bafybeifo5db5a5a73n5h2jwbf2ui6fkcavxc4wxio4d2hw2ykmg25hjdfi` | Test and debug tendermint reset mechanism. | -| skill/valory/register_reset_recovery_abci/0.1.0 | `bafybeiaw6cregh6whu2wbwoh2r7j6z5fzp4gdvxqw3dqhjzgmtqwutm5re` | ABCI application for dummy skill that registers and resets | -| agent/valory/register_reset_recovery/0.1.0 | `bafybeigbkq5bz5f66zzsdhr3zaffj5sehft62ykojrbr3e6rb3bkw7chfa` | Agent to showcase hard reset as a recovery mechanism. | -| contract/valory/multicall2/0.1.0 | `bafybeih635opvafoeojdbt5hwfdyrwzrlwbs44nvck7zs2mfc2oj7ehiie` | The MakerDAO multicall2 contract. | -| protocol/open_aea/signing/1.0.0 | `bafybeibqlfmikg5hk4phzak6gqzhpkt6akckx7xppbp53mvwt6r73h7tk4` | A protocol for communication between skills and decision maker. | -| protocol/valory/acn/1.1.0 | `bafybeignmc5uh3vgpuckljcj2tgg7hdqyytkm6m5b6v6mxtazdcvubibva` | The protocol used for envelope delivery on the ACN. | -| protocol/valory/http/1.0.0 | `bafybeifyoio7nlh5zzyn5yz7krkou56l22to3cwg7gw5v5o3vxwklibhty` | A protocol for HTTP requests and responses. | -| protocol/valory/ledger_api/1.0.0 | `bafybeibo4bdtcrxi2suyzldwoetjar6pqfzm6vt5xal22ravkkcvdmtksi` | A protocol for ledger APIs requests and responses. | -| protocol/valory/contract_api/1.0.0 | `bafybeidv6wxpjyb2sdyibnmmum45et4zcla6tl63bnol6ztyoqvpl4spmy` | A protocol for contract APIs requests and responses. | -| connection/valory/http_client/0.23.0 | `bafybeidykl4elwbcjkqn32wt5h4h7tlpeqovrcq3c5bcplt6nhpznhgczi` | The HTTP_client connection that wraps a web-based client connecting to a RESTful API specification. | -| connection/valory/ledger/0.19.0 | `bafybeicgfupeudtmvehbwziqfxiz6ztsxr5rxzvalzvsdsspzz73o5fzfi` | A connection to interact with any ledger API and contract API. | -| connection/valory/p2p_libp2p_client/0.1.0 | `bafybeidwcobzb7ut3efegoedad7jfckvt2n6prcmd4g7xnkm6hp6aafrva` | The libp2p client connection implements a tcp connection to a running libp2p node as a traffic delegate to send/receive envelopes to/from agents in the DHT. | +| protocol/valory/abci/0.1.0 | `bafybeihmzlmmb4pdo3zkhg6ehuyaa4lhw7bfpclln2o2z7v3o6fcep26iu` | A protocol for ABCI requests and responses. | +| connection/valory/abci/0.1.0 | `bafybeih4lb2myvtypnfeji5jmgikmmazpgl3vyf5sy7oe66ji2zfjj6ily` | connection to wrap communication with an ABCI server. | +| connection/valory/ipfs/0.1.0 | `bafybeigjtca6b5wwiobl37es3wllzt6ai3qef5gqxzfy5fmmc65jkbnec4` | A connection responsible for uploading and downloading files from IPFS. | +| contract/valory/gnosis_safe_proxy_factory/0.1.0 | `bafybeiehjccqvhrcarhahhyyrshaifoipfqwvpxjucpucslp22l2wc3sl4` | Gnosis Safe proxy factory (GnosisSafeProxyFactory) contract | +| contract/valory/component_registry/0.1.0 | `bafybeiepywewigowj533f55orx7oys3kk5lgdc247p2267scqfyp4gnqle` | Component registry contract | +| contract/valory/agent_registry/0.1.0 | `bafybeignghdk7oqvyg722gz66tbuj2vj4vkatguj4b6lf5fqzqxkktcke4` | Agent registry contract | +| contract/valory/registries_manager/0.1.0 | `bafybeihcilb27ekgoplmc43iog2zrus63fufql4rly2umbuj573nu3zpg4` | Registries Manager contract | +| contract/valory/service_manager/0.1.0 | `bafybeibmqewfh5wnayopneyv4vx35n5k7loavzmcazyevntdoskw7vasom` | Service Manager contract | +| skill/valory/test_ipfs_abci/0.1.0 | `bafybeigcwbshni7jt2wo7stkln2ku2pxa4z65kqy3xv7bucld63o5aftxe` | IPFS e2e testing application. | +| agent/valory/test_ipfs/0.1.0 | `bafybeigbtb5apxqgqncxhjf7ngqfskcapaahtc4lxj3hig3q7w36axxrr4` | Agent for testing the ABCI connection. | +| contract/valory/service_registry/0.1.0 | `bafybeieeuruq7dp4b6souetv5ce7wlm52pw7vyrxuhqa7kuy5m3rwwxks4` | Service Registry contract | +| protocol/valory/tendermint/0.1.0 | `bafybeig6g6twajlwssfbfp5rlnu5mwzuu5kgak5cs4fich7rlkx6whesnu` | A protocol for communication between two AEAs to share tendermint configuration details. | +| protocol/valory/ipfs/0.1.0 | `bafybeiedxeismnx3k5ty4mvvhlqideixlhqmi5mtcki4lxqfa7uqh7p33u` | A protocol specification for IPFS requests and responses. | +| skill/valory/abstract_abci/0.1.0 | `bafybeial6drwstqlvuizgtouc4uqgxvutwryfu7yohondemd6bd7cw3jzm` | The abci skill provides a template of an ABCI application. | +| contract/valory/gnosis_safe/0.1.0 | `bafybeiegkl6zrbvlbpwmoziw4hfkocjfqdqphkmpgow7ovsmv7bwa3f4pe` | Gnosis Safe (GnosisSafeL2) contract | +| skill/valory/abstract_round_abci/0.1.0 | `bafybeicrzndcdbue34yxwwb4hmmdhgzw4owcdcdag3ifj6thpx5wie3dp4` | abstract round-based ABCI application | +| contract/valory/multisend/0.1.0 | `bafybeig5byt5urg2d2bsecufxe5ql7f4mezg3mekfleeh32nmuusx66p4y` | MultiSend contract | +| skill/valory/transaction_settlement_abci/0.1.0 | `bafybeifpnkwgwpzz6uwrvfgurm26allr6shjfbp7bfbrxwy64sw3nf3fsa` | ABCI application for transaction settlement. | +| skill/valory/registration_abci/0.1.0 | `bafybeihjlapvviakobxg7aa5qubgqoz6xurlhu7xxtnrg5ah3ag2qj626i` | ABCI application for common apps. | +| skill/valory/reset_pause_abci/0.1.0 | `bafybeibnwjcjx4lluf4cwb6es5peelu3gm7vrzlieygrzpbjlubxpvbvzy` | ABCI application for resetting and pausing app executions. | +| skill/valory/termination_abci/0.1.0 | `bafybeifdtxgldw33kwvsavcituzewwbr6iqfcsgk5qouqfhpwdrivyyyom` | Termination skill. | +| skill/valory/counter/0.1.0 | `bafybeieunypccr354dbj7s5qcrxrwvkdci5wij5tn5nkqtk5twausre6zy` | The ABCI Counter application example. | +| skill/valory/counter_client/0.1.0 | `bafybeignmckuvyuzvnwuhuor7oewy6yu7mpqht6ot46tznwujj5uu5ghc4` | A client for the ABCI counter application. | +| skill/valory/register_reset_abci/0.1.0 | `bafybeihqsxv6yrz7pjccmwq2i4gcyaivnzts2h77a73g2diebf6gao4rmu` | ABCI application for dummy skill that registers and resets | +| skill/valory/register_termination_abci/0.1.0 | `bafybeiadiu5cjrwk5ceuiunzjbstwtzr3t6g4ptqoqg4vaxfgfgax2jd5e` | ABCI application for dummy skill that registers and resets | +| skill/valory/test_abci/0.1.0 | `bafybeibey5n6lviqytacqbm4jlu6qtkrz3edun45o7sbvdpluvdfolxo2q` | ABCI application for testing the ABCI connection. | +| agent/valory/abstract_abci/0.1.0 | `bafybeicojdd6vpnsw3dyzbh3j7rs5ubihvd6y4tgrkbryrofqiyk54awki` | The abstract ABCI AEA - for testing purposes only. | +| agent/valory/counter/0.1.0 | `bafybeidueagnkdtcw4ptf6wjhqw53qsclmgqubw4eovxqip4eqdwtcp7sa` | The ABCI Counter example as an AEA | +| agent/valory/counter_client/0.1.0 | `bafybeiczbvqzoaltjd6pfwskniwqigubkarbshk2khtrwaz5vb5biwvw44` | The ABCI Counter example as an AEA | +| agent/valory/register_reset/0.1.0 | `bafybeigrvrcrpy4zmifvej33zhhoxrvsxfsi2ebsic6a3kdl4hy6angmve` | Register reset to replicate Tendermint issue. | +| agent/valory/register_termination/0.1.0 | `bafybeicjz22y4ih4oaouxijbcc2ycfxh2wg2ggs5svg4piiex6bk7222ce` | Register terminate to test the termination feature. | +| agent/valory/registration_start_up/0.1.0 | `bafybeihj222uo24chybhkdq6xmidw2eyng4ehnhzktg4x6lruienxw7sue` | Registration start-up ABCI example. | +| agent/valory/test_abci/0.1.0 | `bafybeih6pwoej6yxng7imwwio3mge36wxrffxmpfz4llcnwspx5wmk2cvi` | Agent for testing the ABCI connection. | +| service/valory/counter/0.1.0 | `bafybeiehjaxonhm45oagbuqdrc46vgxfzo75bx7kjnejw55qbwfzjmpyfi` | A set of agents incrementing a counter | +| service/valory/register_reset/0.1.0 | `bafybeigbgqdhpilkxw7cprkdpxqhnakjd63howrdiwcpalsylpwrvvsvem` | Test and debug tendermint reset mechanism. | +| skill/valory/register_reset_recovery_abci/0.1.0 | `bafybeihyfo3jxvsw6vuivdn72lobjq57k42wuwixt7qj6qrh2u5j534qgq` | ABCI application for dummy skill that registers and resets | +| agent/valory/register_reset_recovery/0.1.0 | `bafybeigwsw6eglzvfthyeyaviwvpjrbdlnma4d4fzbis7obgdnxeq5ew5q` | Agent to showcase hard reset as a recovery mechanism. | +| contract/valory/multicall2/0.1.0 | `bafybeif7c2sfjpjjueqevs5rmfpshlkbtrertdy2euvptecnzy2ioru7ue` | The MakerDAO multicall2 contract. | +| skill/valory/slashing_abci/0.1.0 | `bafybeievvfagzeod4ivbx7dmnmybrmodkzuav7kjz4wjjr3cagslsyh6oy` | Slashing skill. | +| skill/valory/offend_abci/0.1.0 | `bafybeifhczaajqghtwo754aukhy2uyollmksgxnofowem67wy5ie5ezmvm` | Offend ABCI application. | +| skill/valory/offend_slash_abci/0.1.0 | `bafybeidb6v5jmjmsiw5ydfoolzhl7w7clz2iazyuz5pikq7qmoq3fbxpne` | ABCI application used in order to test the slashing abci | +| agent/valory/offend_slash/0.1.0 | `bafybeiafes7lwjd7zuvgjq6o2h752oi5wtbah6tgjstvymagb3xd6rtwse` | Offend and slash to test the slashing feature. | +| contract/valory/erc20/0.1.0 | `bafybeib7ctk3deleyxayrqvropewefr2muj4kcqe3t3wscak25bjmxnqwe` | The scaffold contract scaffolds a contract to be implemented by the developer. | +| contract/valory/service_registry_token_utility/0.1.0 | `bafybeifdia2y5546tvk6xzxeaqzf2n5n7dutj2hdzbgenxohaqhjtnjqm4` | The scaffold contract scaffolds a contract to be implemented by the developer. | +| protocol/open_aea/signing/1.0.0 | `bafybeie7xyems76v5b4wc2lmaidcujizpxfzjnnwdeokmhje53g7ym25ii` | A protocol for communication between skills and decision maker. | +| protocol/valory/acn/1.1.0 | `bafybeic2pxzfc3voxl2ejhcqyf2ehm4wm5gxvgx7bliloiqi2uppmq6weu` | The protocol used for envelope delivery on the ACN. | +| protocol/valory/http/1.0.0 | `bafybeiejoqgv7finfxo3rcvvovrlj5ccrbgxodjq43uo26ylpowsa3llfe` | A protocol for HTTP requests and responses. | +| protocol/valory/ledger_api/1.0.0 | `bafybeige5agrztgzfevyglf7mb4o7pzfttmq4f6zi765y4g2zvftbyowru` | A protocol for ledger APIs requests and responses. | +| protocol/valory/contract_api/1.0.0 | `bafybeialhbjvwiwcnqq3ysxcyemobcbie7xza66gaofcvla5njezkvhcka` | A protocol for contract APIs requests and responses. | +| connection/valory/http_client/0.23.0 | `bafybeiddrfvomrmgvh5yuv2coq7ci72wcdf663stayi3m5aawnj4srggce` | The HTTP_client connection that wraps a web-based client connecting to a RESTful API specification. | +| connection/valory/ledger/0.19.0 | `bafybeia47rr37ianvwsh77tjjpv3nwif5sywhhy2fbdshnz4a2icwln76a` | A connection to interact with any ledger API and contract API. | +| connection/valory/p2p_libp2p_client/0.1.0 | `bafybeihge56dn3xep2dzomu7rtvbgo4uc2qqh7ljl3fubqdi2lq44gs5lq` | The libp2p client connection implements a tcp connection to a running libp2p node as a traffic delegate to send/receive envelopes to/from agents in the DHT. | diff --git a/docs/questions-and-answers.md b/docs/questions-and-answers.md index c8de583a03..dc18491c22 100644 --- a/docs/questions-and-answers.md +++ b/docs/questions-and-answers.md @@ -23,33 +23,26 @@ ??? note "Can I reuse the same {{fsm_app}} multiple times when creating a composed {{fsm_app}}?" No. The Open Autonomy framework currently only supports a single instance of a given {{fsm_app}} in a composition. - ??? note "Composability, extensibility and reusability are advantages also present in other tech stacks. What makes Autonolas different?" Autonolas is not just a framework where devs can build on: it is a complete, novel ecosystem that provides an SDK, a reward system for developers and operators and a governance protocol on top, all of them decentralized. In the same way companies like Apple or Google offer SDKs to accelerate devs work plus an app store to monetize their work, Autonolas offers the same capabilities but in a decentralized way: developers register components, operators run services that use those components, consumers use and pay for those services so both developers and operators are compensated for their work. And all the parameters that govern the network can be voted on. - ??? note "How do agents communicate with other agents?" - Different forms of communication are used depending on the service status. Before the agents can establish a temporary blockchain (Tendermint network) that serves as consensus engine they need to exchange the necessary information with others in order to be able to do so. This information includes the network address of their Tendermint node and the associated public key. They do so by connecting to the Agent Communication Network (ACN), where they can send messages to other agents, in this case requesting their Tendermint configuration details, using their on-chain registered address. The list of registered addresses is retrieved from the the service registry smart contract and can be used to filter out request coming from any party that is not registered to operate in this service as well. Once all configurations have been exchanged the Tendermint network can be established and is used as a consensus engine. - + Different forms of communication are used depending on the service status. Before the agents can establish a temporary blockchain (Tendermint network) that serves as consensus engine they need to exchange the necessary information with others in order to be able to do so. This information includes the network address of their Tendermint node and the associated public key. They do so by connecting to the Agent Communication Network (ACN), where they can send messages to other agents, in this case requesting their Tendermint configuration details, using their on-chain registered address. The list of registered addresses is retrieved from the service registry smart contract and can be used to filter out request coming from any party that is not registered to operate in this service as well. Once all configurations have been exchanged the Tendermint network can be established and is used as a consensus engine. ??? note "Can services use other services?" Yes, an agent service can be composed from other agent services, analogously to microservices. Sub-services can deliver all sorts of results which are consumed by a higher level service to create a higher level outcome. - ??? note "How do services communicate with other services?" Services use a native message protocol based on protobuf that allows them to have arbitrary message-based communication between compatible agents in the network. The network they use for this is the Agent Communication Network (ACN), and protocols define the structure of communication flow, ranging from simple atomic request-response pairs to arbitrarily complicated dialogues (e.g. FIPA). To communicate with traditional services, agents can both make API calls and expose REST APIs. - ??? note "What happens when agents are deployed?" - Agents are be able to interact with the Autonolas on-chain Protocol so they can monetize their work and connect to other services. Apart from that, "island deployments" can also be operated, which are services that run as one-off services, not anchored in the protocol. - + Agents are able to interact with the Autonolas on-chain Protocol so they can monetize their work and connect to other services. Apart from that, "island deployments" can also be operated, which are services that run as one-off services, not anchored in the protocol. ??? note "How many composition levels does Open Autonomy offer?" Composition starts at the component level of the agents (multiple rounds make a skill), then continues on agent level (multiple skills make an agent) and ends at service level (multiple agents make a service). - ??? note "How do agents settle a transaction?" 1. Negotiation happens through Tendermint messages. 2. A threshold of agents agree on a transaction hash. @@ -59,26 +52,20 @@ 6. All agents wait for the transaction to be mined and validate the output. 7. Done - - ??? note "Do all agent services have to be implemented as {{fsm_app}}s with Open Autonomy?" Certainly not. For extremely simple applications, you can consider implementing an agent service by appropriately extending the `ABCIHandler` class to handle the consensus gadget callbacks, and if required, manually implement the agent `Behaviours` that execute client calls to the consensus gadget. However, **we strongly advise against this approach**, as the complexity, maintainability and composability of the resulting service will be severely affected. - ## Security ??? note "How are agent services run?" Agent services are composed of multiple agents that run the same code and agree on its output. These agents are executed by independent operators. Each operator can select and setup the infrastructure that best suits their needs. - ??? note "What happens if my node is hacked?" As in any other online service, nodes are exposed to the risk of being breached. At the individual level, the framework does not provide a solution to this and it’s up to the agent operator to keep the agent safe. At the service level, on the other hand, services are secured in two ways: * Each agent service implements a custom protocol that expects a very narrow message flow, so a hypothetical agent running malicious code would need to express its intentions within this protocol, otherwise the other agents will ignore its messages. * Even in the case of an agent sending valid, malicious messages in the service, the decentralized nature of services means that the majority threshold of agents (2/3 + 1) must agree before committing a malicious transaction, so it is not enough to breach an individual agent. - - ## Costs ??? note "How much does it cost to run an agent service using the framework?" @@ -220,3 +207,21 @@ + +## Ethereum topics + +??? note "How does EIP-1559 transaction pricing mechanism work?" + EIP-1559 has introduced significant changes in how the transaction pricing is determined. Previously, setting the `gasPrice` was sufficient; now, two new parameters have to be specified, `maxFeePerGas` and `maxPriorityFeePerGas`. + + The new pricing structure comprises three key elements: + + - **Base Fee**: This fee is determined autonomously by the network and is subsequently burned. It aims to target 50% full blocks and is adjusted based on the contents of the most recent confirmed block. Depending on block usage, the Base Fee automatically increases or decreases. + - **Max Priority Fee Per Gas**: This fee is optional and set by the user. It is paid directly to miners. Although technically optional, most network participants estimate that transactions generally require a minimum 2.0 GWEI tip to be competitive for inclusion. + - **Max Fee Per Gas**: This parameter is the absolute maximum amount you are willing to pay per unit of gas to have your transaction included in a block. If the sum of the Base Fee and Max Priority Fee exceeds the Max Fee, the Max Priority Fee is reduced to maintain the upper bound of the Max Fee. A heuristic formula for Max Fee calculation is: Max Fee = (2 * Base Fee) + Max Priority Fee. Doubling the Base Fee in this calculation ensures that your transaction remains marketable for six consecutive 100% full blocks. + + Transactions containing these new parameters are designated as Type 2, while legacy transactions retaining the original Gas Price field are referred to as Type 0. Notably, EIP-1559 does not alter the Gas Limit, which remains the maximum amount of gas a transaction is authorized to consume. + + For further information, please refer to the [EIP-1559 FAQ](https://notes.ethereum.org/@vbuterin/eip-1559-faq) + +??? note "How does a delegate call differ from a call in the context of Safe transactions?" + When you initiate a delegate call in a Safe transaction (i.e., with the operation set to `delegatecall`), it essentially instructs the Safe to "load the code from the specified address and run it." In other words, it retrieves the code from the contract address provided and executes it. This operation allows for dynamic code execution, enabling flexibility in Smart Contract interactions. diff --git a/docs/upgrading.md b/docs/upgrading.md index 889dc60653..d6599600ae 100644 --- a/docs/upgrading.md +++ b/docs/upgrading.md @@ -5,13 +5,157 @@ Below we describe the additional manual steps required to upgrade between differ # Open Autonomy +## `v0.13.9` to `v0.13.9.post1` + +No backwards incompatible changes + +## `v0.13.8` to `v0.13.9` + +No backwards incompatible changes + +## `v0.13.7` to `v0.13.8` + +No backwards incompatible changes + +## `v0.13.6` to `v0.13.7` + +No backwards incompatible changes + +## `v0.13.5` to `v0.13.6` + +No backwards incompatible changes + +## `v0.13.4` to `v0.13.5` + +No backwards incompatible changes + +## `v0.13.3` to `v0.13.4` + +No backwards incompatible changes + +## `v0.13.2` to `v0.13.3` + +No backwards incompatible changes + +## `v0.13.1` to `v0.13.2` + +- The usage `--password` of flag has been deprecated on `autonomy deploy` command group. Use `OPEN_AUTONOMY_PRIVATE_KEY_PASSWORD` environment variable to export the private key password string when running `autonomy deploy build/run` commands. + +## `v0.13.1` to `v0.13.1.post1` + +No backwards incompatible changes + +## `v0.13.0` to `v0.13.1` + +- This release introduces support for defining service level dependencies, which means you can define python dependencies at the service level which will take priority over the agent or component level dependencies. The `dependencies` parameter is currently optional to make the upgrading easier. But this will be required in the next release, so please update your services accordingly. + +## `v0.12.1.post4` to `v0.13.0` + +- `open-aea-web3` has been replaced with `web3py` +- `protobuf` has been bumped to `protobuf>=4.21.6,<5.0.0`, this means you will have to bump your protocol generator to `v24.3` and generate your protocol packages again. +- The `valory/open-autonomy` image will use Python 3.11 as default interpreter for running agents + +## `v0.12.1.post3` to `v0.12.1.post4` + +No backwards incompatible changes + +## `v0.12.1.post2` to `v0.12.1.post3` + +No backwards incompatible changes + +## `v0.12.1.post1` to `v0.12.1.post2` + +No backwards incompatible changes + +## `v0.12.1` to `v0.12.1.post1` + +- Environment variable names have changed for custom contract address, refer to the `mint/service` CLI tools documentation regarding the changes. + +## `v0.12.0` to `v0.12.1` + +No backwards incompatible changes + +## `v0.11.1` to `v0.12.0` + +- Renamed the `background_behaviour_cls` in `AbstractRoundBehaviour` to `termination_behaviour_cls`. + *Should be taken into consideration for all the apps that are utilizing the termination.* +- Renamed the `background_behaviour` in `AbstractRoundBehaviour` to `termination_behaviour`. +- Renamed the `is_background_behaviour_set` property in `AbstractRoundBehaviour` to `is_termination_set`. +- Renamed the `background_round_cls` argument of the `add_termination` method in `AbciApp` to `termination_round_cls`. + *Should be taken into consideration for all the apps that are utilizing the termination.* +- Renamed the `background_round_cls` attribute of the `AbciApp` to `termination_round_cls`. +- Renamed the `_background_round` attribute of the `AbciApp` to `_termination_round`. +- Renamed the `background_round` property of the `AbciApp` to `termination_round`. +- The `AbstractRound` class now requires a `SkillContext` positional argument. + To accommodate this change, + all round tests will need to be modified to include a mocked context in addition to the synchronized data. + +1 && 4 should be taken into consideration for all the apps that are utilizing the termination. + +## `v0.11.0` to `v0.11.1` + +The `autonomy deploy run` command now handles the exists from deployment and to do this we're running the deployments in detached mode and waiting for the user to cancel what that means is from now on when running the deployments the logs won't be printed out by default. If you want to check out the logs for containers you can use `docker logs` command. + +## `v0.10.11.post1` to `v0.11.0` + +- `web3py` has been replaced with `open-aea-web3` and we forked this from `web3py@v6.0.0`, that means the method names will use the `snake_case` and the `camelCase` naming has been deprecated +- Support for `Python 3.7` has been deprecated + +## `v0.10.11` to `v0.10.11.post1` + +No backwards incompatible changes + +## `v0.10.10.post1` to `v0.10.11` + +No backwards incompatible changes + +## `v0.10.10` to `v0.10.10.post1` + +No backwards incompatible changes + +## `v0.10.9` to `v0.10.10` + +No backwards incompatible changes + +## `v0.10.8` to `v0.10.9` + +No backwards incompatible changes + +## `v0.10.7` to `v0.10.8` + +No backwards incompatible changes + +## `v0.10.6` to `v0.10.7` + +No backwards incompatible changes + +## `v0.10.5.post2` to `v0.10.6` + +No backwards incompatible changes + +## `v0.10.5.post1` to `v0.10.5.post2` + +No backwards incompatible changes + +## `v0.10.4` to `v0.10.5.post1` + +No backwards incompatible changes + +## `v0.10.3` to `v0.10.4` + +No backwards incompatible changes + +## `v0.10.2` to `v0.10.3` + +No backwards incompatible changes + ## `v0.10.1` to `v0.10.2` No backwards incompatible changes ## `v0.10.0.post2` to `v0.10.1` -No backwards incompatible changes +This version fixes a bug on the build tools which will introduce a change on the expected output of the deployment builds. Before this bug fix the deployment tools did not index the agents on the manual builds, which lead to the behaviour where if you built the deployment using just one key or `--n` flag the agents were indexed from `0` instead. With this bug fix the deployment tools will use the `all_participants` list to index the agents before building the deployments. ## `v0.10.0.post1` to `v0.10.0.post2` diff --git a/docs/using_stack_deployment.md b/docs/using_stack_deployment.md index e3dd64e14a..1166da4ee1 100644 --- a/docs/using_stack_deployment.md +++ b/docs/using_stack_deployment.md @@ -85,7 +85,7 @@ terraform apply # deploy resources and approve when prompted. ### Post Cluster Deployment Setup -Once the cluster has been deployed, we need to go ahead and actually deploy our application the cluster. We have included a number of convenience commands to speed this process up. +Once the cluster has been deployed, we need to go ahead and actually deploy our application to the cluster. We have included a number of convenience commands to speed this process up. Depending upon the Cloud Provider selected above, the user must now point their Kubectl at the newly deployed cluster as so; diff --git a/liccheck.ini b/liccheck.ini deleted file mode 100644 index 91bc90d82c..0000000000 --- a/liccheck.ini +++ /dev/null @@ -1,106 +0,0 @@ -; some useful links: -; - https://janelia-flyem.github.io/licenses.html -; - https://dwheeler.com/essays/floss-license-slide.html - -; Authorized and unauthorized licenses in LOWER CASE -[Licenses] -authorized_licenses: - ; aliases for MIT License - MIT - MIT license - https://opensource.org/licenses/MIT - License :: OSI Approved :: MIT - - ; aliases for BSD License (and variants) - BSD - BSD license - new BSD - (new) BSD - new BDS license - simplified BSD - 3-Clause BSD - BSD-3-Clause - BSD 3-Clause - BSD-2-Clause - BSD-like - BSD-2-Clause or Apache-2.0 - BSD, Public Domain - - ; Apache - Apache Software - - ; aliases for Apache License version 2.0 - Apache 2.0 - Apache-2.0 - Apache License 2.0 - Apache License, Version 2.0 - Apache License Version 2.0 - Apache2 - ASL 2 -; some packages use 'Apache Software' as license string, -; which is ambiguous. However, 'Apache Software' -; will likely match with 'Apache 2.0' - Apache Software - BSD, Public Domain, Apache - http://www.apache.org/licenses/LICENSE-2.0 - -; PSF (BSD-style) - Python Software Foundation - PSF - - ; other permissive licenses - Historical Permission Notice and Disclaimer (HPND) - HPND - ISC - BSD or Apache License, Version 2.0 - Modified BSD - Expat - Public Domain - -unauthorized_licenses: -; aliases for MPL 2.0 - MPL-2.0 - MPL 2.0 - Mozilla Public License 2.0 (MPL 2.0) - -; Section 8 of https://www.mozilla.org/en-US/MPL/2.0/Revision-FAQ/ - MPL 1.1 - MPL-1.1 - -; http://www.gnu.org/licenses/license-list.en.html#apache2 - GPLv2 - GPLv2+ - GNU General Public License v2 or later (GPLv2+) - -; LGPL - LGPL - GNU Library or Lesser General Public License (LGPL) - -; LGPLv2.1 - LGPLv2.1 - LGPLv2.1+ - GNU Lesser General Public License v2 or later (LGPLv2+) - -; LGPLv3 - GNU Lesser General Public License v3 (LGPLv3) - LGPLv3 - -; GPL v3 - GPL v3 - GPLv3+ - GNU General Public License v3 (GPLv3) - -[Authorized Packages] -gym: >=0.15 -;filelock is public domain -filelock: >=3.0.12 -fetchai-ledger-api: >=0.0.1 -chardet: >=3.0.4 -certifi: >=2019.11.28 -;TODO: the following are confilctive packages that need to be sorted -; sub-dep of open-aea-ledger-ethereum-hwi -hidapi: >=0.13.1 -; shows in pip freesze but not referenced on code -paramiko: >=3.1.0 -; sub-dep of docker-compose -websocket-client: >=0.59.0 diff --git a/mkdocs.yml b/mkdocs.yml index 8f25a42d21..de6ff676ba 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -5,18 +5,33 @@ repo_url: https://github.com/valory-xyz/open-autonomy site_author: developer@valory.xyz edit_uri: edit/main/docs/ +# TODO: Set true after fixing the material dependency +strict: false + + theme: name: 'material' + language: en + favicon: images/favicon.ico + logo: images/logo.svg + icon: + admonition: + abstract: material/book-open-variant features: - - navigation.top - navigation.indexes + - navigation.top + - navigation.tracking + - navigation.footer + - search.highlight + - search.share + - search.suggest - content.code.copy - content.code.annotate + - content.tabs.link extra_css: - stylesheets/extra.css -strict: true nav: - Home: 'index.md' @@ -36,13 +51,7 @@ nav: - Define the service: 'guides/define_service.md' - Publish and mint packages: 'guides/publish_mint_packages.md' - Deploy the service: 'guides/deploy_service.md' - - Demo agent services: - - 'demos/index.md' - - Hello World demo: 'demos/hello_world_demo.md' - - Price Oracle Demo: - - Introduction: 'demos/price_oracle_intro.md' - - Technical Details: 'demos/price_oracle_technical_details.md' - - FSM Specification: 'demos/price_oracle_fsms.md' + - Bumping the service: 'guides/bumping_services.md' - Key concepts: - 'key_concepts/index.md' - Autonomous economic agents: 'key_concepts/aea.md' @@ -65,6 +74,7 @@ nav: - Analise and test: 'configure_service/analise_test.md' - Advanced reference: - 'advanced_reference/index.md' + # - publish fetch: 'guides/publish_fetch_packages.md' - Commands: - autonomy deploy: 'advanced_reference/commands/autonomy_deploy.md' - autonomy build-image: 'advanced_reference/commands/autonomy_build-image.md' @@ -79,11 +89,12 @@ nav: - Execution replay: 'advanced_reference/developer_tooling/execution_replay.md' - Benchmarking: 'advanced_reference/developer_tooling/benchmarking.md' - Debugging in the cluster: 'advanced_reference/developer_tooling/debugging_in_the_cluster.md' + - Debugging using Tenderly: 'advanced_reference/developer_tooling/debugging_using_tenderly.md' - Deployment: - Container Control Flow: 'control_flow.md' - - Local Deployment: 'application_deployment.md' - - Cloud Deployment: 'using_stack_deployment.md' - Using custom images in a deployment: 'advanced_reference/use_custom_images.md' + - Using custom dockerfile: advanced_reference/developer_tooling/custom_agent_image.md + - On Chain Addresses: 'advanced_reference/on_chain_addresses.md' - API: - Library: - Constants: 'api/constants.md' @@ -239,11 +250,7 @@ nav: - Payload Tools: 'api/skills/transaction_settlement_abci/payload_tools.md' - Test Tools: 'api/skills/transaction_settlement_abci/test_tools/integration.md' - Exceptions: 'exceptions.md' - - Miscellaneous: - - Ethereum: 'ethereum_specifics.md' - - Delegate call vs call: 'delegate_call.md' - - Debugging Using Tenderly: 'debugging.md' - - Package list: 'package_list.md' + - Package list: 'package_list.md' - Version: 'version.md' - Upgrading: 'upgrading.md' - FAQ: 'questions-and-answers.md' @@ -252,39 +259,64 @@ nav: plugins: - macros: on_error_fail: true + on_undefined: strict - search + markdown_extensions: + - admonition + - attr_list - pymdownx.details + - pymdownx.keys - pymdownx.superfences - pymdownx.tabbed: alternate_style: true - pymdownx.highlight - pymdownx.emoji: - emoji_index: !!python/name:materialx.emoji.twemoji - emoji_generator: !!python/name:materialx.emoji.to_svg - - admonition - - pymdownx.arithmatex - - attr_list + emoji_index: !!python/name:material.extensions.emoji.twemoji + emoji_generator: !!python/name:material.extensions.emoji.to_svg + - pymdownx.arithmatex: + generic: true + - pymdownx.superfences: + custom_fences: + - name: mermaid + class: mermaid + format: !!python/name:pymdownx.superfences.fence_code_format - def_list - md_in_html + - toc: + title: On this page + toc_depth: 3 -extra: - open_aea: '[Open AEA](https://github.com/valory-xyz/open-aea)' - open_aea_doc: '[Open AEA documentation](https://open-aea.docs.autonolas.tech)' - open_aea_api: '[Open AEA API](https://open-aea.docs.autonolas.tech/api/)' - fsm_app: 'FSM App' - open_autonomy: '[Open Autonomy](https://github.com/valory-xyz/open-autonomy)' - open_autonomy_api: '[Open Autonomy API](https://docs.autonolas.network/)' - on_chain_frontend: '[on-chain protocol frontend](https://protocol.autonolas.network/)' - open_aea_repository: '[Open AEA repository](https://github.com/valory-xyz/open-aea)' - open_autonomy_repository: '[Open Autonomy repository](https://github.com/valory-xyz/open-aea)' - price_oracle_service: 'Price Oracle service' +extra: + open_aea: '[Open AEA](https://github.com/valory-xyz/open-aea)' + open_aea_doc: '[Open AEA documentation](https://open-aea.docs.autonolas.tech)' + open_aea_api: '[Open AEA API](https://open-aea.docs.autonolas.tech/api)' + fsm_app: 'FSM App' + open_autonomy: '[Open Autonomy](https://github.com/valory-xyz/open-autonomy)' + open_autonomy_api: '[Open Autonomy API](https://docs.autonolas.network)' + open_aea_repository: '[Open AEA repository](https://github.com/valory-xyz/open-aea)' + open_autonomy_repository: '[Open Autonomy repository](https://github.com/valory-xyz/open-autonomy)' + autonolas_whitepaper: '[Autonolas Whitepaper](https://www.autonolas.network/documents/whitepaper/Whitepaper%20v1.0.pdf)' + autonolas_protocol: '[Autonolas Protocol](https://docs.autonolas.network/protocol)' + autonolas_protocol_registry_dapp_link: 'https://registry.olas.network' + autonolas_protocol_registry_dapp: '[Autonolas Registry web app](https://registry.olas.network)' + autonolas_protocol_tokenomics_dapp: '[Autonolas Tokenomics web app](https://tokenomics.olas.network)' + social: + - icon: fontawesome/brands/twitter + link: https://twitter.com/autonolas + name: Autonolas on Twitter + - icon: fontawesome/brands/discord + link: https://discord.com/invite/z2PT65jKqQ + name: Autonolas on Discord + - icon: fontawesome/brands/github + link: https://github.com/valory-xyz + name: Autonolas on GitHub -#extra_css: -# - css/my-styles.css extra_javascript: - https://unpkg.com/mermaid@8.10.1/dist/mermaid.min.js - - https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.0/MathJax.js?config=TeX-MML-AM_CHTML + - javascripts/mathjax.js + - https://polyfill.io/v3/polyfill.min.js?features=es6 + - https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js diff --git a/packages/packages.json b/packages/packages.json index 862be79cd7..986ebaae79 100644 --- a/packages/packages.json +++ b/packages/packages.json @@ -1,55 +1,58 @@ { "dev": { - "protocol/valory/abci/0.1.0": "bafybeig3dj5jhsowlvg3t73kgobf6xn4nka7rkttakdb2gwsg5bp7rt7q4", - "connection/valory/abci/0.1.0": "bafybeih2l6ssf5ebkvgbag3hx2pd22shytszqavveib2e2s6rv4va5khv4", - "connection/valory/ipfs/0.1.0": "bafybeihubpyw2t3bwncz3l7jt4gf5xvfydwmob463vvgf3ikkhlwxakm3m", - "contract/valory/gnosis_safe_proxy_factory/0.1.0": "bafybeierle6peb4a5cw3tncgondwhgesomzg7tedkb5cuos2zm462asbdi", - "contract/valory/component_registry/0.1.0": "bafybeifeujuzp56zzdhyvxitnaakqetcqhbqr2x6jxnhj7ahzm7pb2y7uy", - "contract/valory/agent_registry/0.1.0": "bafybeifdrul5qvk5hj4ggy63ff3smt6wc4c67srnqxxfpbz3jsgbpuavgy", - "contract/valory/registries_manager/0.1.0": "bafybeibnvf4z2oi344lsrxcfav3q3udlzokdfa62yc5oui2nuxwupezu7u", - "contract/valory/service_manager/0.1.0": "bafybeihvogcziooqau7n22tejzan2baghjaodkb2u74i3aao7ffomk4aem", - "skill/valory/test_ipfs_abci/0.1.0": "bafybeic7ma7ipbzqno5hvv25aif6rqvmi7gb6vj2kpjbph7jrzidehxose", - "agent/valory/test_ipfs/0.1.0": "bafybeiedrr6izfvibnwkedsx2v3nmcd5jwomk5k7xralk6nbumiqvznaou", - "contract/valory/service_registry/0.1.0": "bafybeiatzikdgcjteti6xeid4bvofszuavxb4fnczx33lcsvlaui4wpwua", - "protocol/valory/tendermint/0.1.0": "bafybeicusvezoqlmyt6iqomcbwaz3xkhk2qf3d56q5zprmj3xdxfy64k54", - "protocol/valory/ipfs/0.1.0": "bafybeic72ncgqbzoz2guj4p4yjqulid7mv6yroeh65hxznloamoveeg7hq", - "skill/valory/abstract_abci/0.1.0": "bafybeifuclb6cikagtg2zn7dkjnnv3f7re2tfgzk6c4h3scgyzaaqeg55m", - "contract/valory/gnosis_safe/0.1.0": "bafybeifvqalsuyetul3ypuolxvxzi5ffxoqdbqpfl3jadqjachsw7qfs74", - "skill/valory/abstract_round_abci/0.1.0": "bafybeigiolzp3i6b3wwuau3yv2h5udqape3i7of73mlm2d6ud22irlkbme", - "contract/valory/multisend/0.1.0": "bafybeigjywkl7hydjsrkogob3xebj2ifhqwmfhhxoeyrndzhhxi5u6amey", - "skill/valory/transaction_settlement_abci/0.1.0": "bafybeifsz2ll7gmy6vmx34t6q5bdv6zzwp5zrehr6di6v3thcpc3sztkta", - "skill/valory/registration_abci/0.1.0": "bafybeigjzfdhhu6ody2qo5v2xjobafujnodklia4zw6bkkhahxtjfo3wby", - "skill/valory/reset_pause_abci/0.1.0": "bafybeieeux3rdlcwgjbdfrluvkhqv26qdparre6pabatietw7juklljil4", - "skill/valory/termination_abci/0.1.0": "bafybeifkl4ab6dnvtsaefe56dbzshmp5mozn7exwcaj2a3wjeq7u3hpezm", - "skill/valory/counter/0.1.0": "bafybeicodfeaolvkppkfoergy4vr5rc5nwntvadr2iebqjklawkvtfea2u", - "skill/valory/counter_client/0.1.0": "bafybeiaqdfulxamdshw7fykfkqvkpvjb5bnmhv7ffrjiwdi4ktiulklx6q", - "skill/valory/hello_world_abci/0.1.0": "bafybeiccrdfvkbrwawroglielcn2pf6vhhz7hoba2ya46ryd5zpmk4al5u", - "skill/valory/register_reset_abci/0.1.0": "bafybeigvyiefdckrxjz67nxwswj73y7dbpj674bca4zd27gdcs6lcy2fku", - "skill/valory/register_termination_abci/0.1.0": "bafybeidv74qpb5k6p5l3fn7qf4bo5o44dx6xfyj2i53rkazq6veyzeos5e", - "skill/valory/test_abci/0.1.0": "bafybeifbskwxg3vz6rl4vcgn4vdeyi5eqxewfnxv4o6ugeyilibmmimbn4", - "agent/valory/abstract_abci/0.1.0": "bafybeibqmgh6v5bfe7covmznjirpaf4r2cw4x7rqmt6toxhqjmuzpan7he", - "agent/valory/counter/0.1.0": "bafybeigkxgd644pzmfigkcprpvv7fkchoj6syyfymvdpeiobpqawfdeq5i", - "agent/valory/counter_client/0.1.0": "bafybeigp4ayq6lsjdeu4pltrksqwcd5lnoqpuhtwznzc5w5y75337ptfo4", - "agent/valory/hello_world/0.1.0": "bafybeidghah5yexnsdxwplnbyq3u3bgl2mmjur2eef4bxenf6ddb3zs2ca", - "agent/valory/register_reset/0.1.0": "bafybeibs3dm6jixfv2m2k67mjduokbxdnod6esjo337tcoa7cudnspr76m", - "agent/valory/register_termination/0.1.0": "bafybeiatofnu3hipdhdiwzhabv3juqhockz5lvvltb6qkzl5ylmpgb66pq", - "agent/valory/registration_start_up/0.1.0": "bafybeifozuszux33n6wtq3urdaqeadzeeobcn4dnddevenri2cgph6k6lm", - "agent/valory/test_abci/0.1.0": "bafybeidjoxttpyoqrdsnmepytxsksm6xcyioancu4yoccuxadul4znd3ry", - "service/valory/counter/0.1.0": "bafybeihzpb3uz7gdclswkusnsbsjgnnmh7xbkwbulkxzpgjteqhfsynvzy", - "service/valory/hello_world/0.1.0": "bafybeigtaxh5zfg32cypqkjvftreivh22sqlrbgw5x3lxjmrf3dyqcioyy", - "service/valory/register_reset/0.1.0": "bafybeifo5db5a5a73n5h2jwbf2ui6fkcavxc4wxio4d2hw2ykmg25hjdfi", - "skill/valory/register_reset_recovery_abci/0.1.0": "bafybeiaw6cregh6whu2wbwoh2r7j6z5fzp4gdvxqw3dqhjzgmtqwutm5re", - "agent/valory/register_reset_recovery/0.1.0": "bafybeigbkq5bz5f66zzsdhr3zaffj5sehft62ykojrbr3e6rb3bkw7chfa", - "contract/valory/multicall2/0.1.0": "bafybeih635opvafoeojdbt5hwfdyrwzrlwbs44nvck7zs2mfc2oj7ehiie" + "protocol/valory/abci/0.1.0": "bafybeihmzlmmb4pdo3zkhg6ehuyaa4lhw7bfpclln2o2z7v3o6fcep26iu", + "connection/valory/abci/0.1.0": "bafybeih4lb2myvtypnfeji5jmgikmmazpgl3vyf5sy7oe66ji2zfjj6ily", + "connection/valory/ipfs/0.1.0": "bafybeigjtca6b5wwiobl37es3wllzt6ai3qef5gqxzfy5fmmc65jkbnec4", + "contract/valory/gnosis_safe_proxy_factory/0.1.0": "bafybeiehjccqvhrcarhahhyyrshaifoipfqwvpxjucpucslp22l2wc3sl4", + "contract/valory/component_registry/0.1.0": "bafybeiepywewigowj533f55orx7oys3kk5lgdc247p2267scqfyp4gnqle", + "contract/valory/agent_registry/0.1.0": "bafybeignghdk7oqvyg722gz66tbuj2vj4vkatguj4b6lf5fqzqxkktcke4", + "contract/valory/registries_manager/0.1.0": "bafybeihcilb27ekgoplmc43iog2zrus63fufql4rly2umbuj573nu3zpg4", + "contract/valory/service_manager/0.1.0": "bafybeibmqewfh5wnayopneyv4vx35n5k7loavzmcazyevntdoskw7vasom", + "skill/valory/test_ipfs_abci/0.1.0": "bafybeigcwbshni7jt2wo7stkln2ku2pxa4z65kqy3xv7bucld63o5aftxe", + "agent/valory/test_ipfs/0.1.0": "bafybeigbtb5apxqgqncxhjf7ngqfskcapaahtc4lxj3hig3q7w36axxrr4", + "contract/valory/service_registry/0.1.0": "bafybeieeuruq7dp4b6souetv5ce7wlm52pw7vyrxuhqa7kuy5m3rwwxks4", + "protocol/valory/tendermint/0.1.0": "bafybeig6g6twajlwssfbfp5rlnu5mwzuu5kgak5cs4fich7rlkx6whesnu", + "protocol/valory/ipfs/0.1.0": "bafybeiedxeismnx3k5ty4mvvhlqideixlhqmi5mtcki4lxqfa7uqh7p33u", + "skill/valory/abstract_abci/0.1.0": "bafybeial6drwstqlvuizgtouc4uqgxvutwryfu7yohondemd6bd7cw3jzm", + "contract/valory/gnosis_safe/0.1.0": "bafybeiegkl6zrbvlbpwmoziw4hfkocjfqdqphkmpgow7ovsmv7bwa3f4pe", + "skill/valory/abstract_round_abci/0.1.0": "bafybeicrzndcdbue34yxwwb4hmmdhgzw4owcdcdag3ifj6thpx5wie3dp4", + "contract/valory/multisend/0.1.0": "bafybeig5byt5urg2d2bsecufxe5ql7f4mezg3mekfleeh32nmuusx66p4y", + "skill/valory/transaction_settlement_abci/0.1.0": "bafybeifpnkwgwpzz6uwrvfgurm26allr6shjfbp7bfbrxwy64sw3nf3fsa", + "skill/valory/registration_abci/0.1.0": "bafybeihjlapvviakobxg7aa5qubgqoz6xurlhu7xxtnrg5ah3ag2qj626i", + "skill/valory/reset_pause_abci/0.1.0": "bafybeibnwjcjx4lluf4cwb6es5peelu3gm7vrzlieygrzpbjlubxpvbvzy", + "skill/valory/termination_abci/0.1.0": "bafybeifdtxgldw33kwvsavcituzewwbr6iqfcsgk5qouqfhpwdrivyyyom", + "skill/valory/counter/0.1.0": "bafybeieunypccr354dbj7s5qcrxrwvkdci5wij5tn5nkqtk5twausre6zy", + "skill/valory/counter_client/0.1.0": "bafybeignmckuvyuzvnwuhuor7oewy6yu7mpqht6ot46tznwujj5uu5ghc4", + "skill/valory/register_reset_abci/0.1.0": "bafybeihqsxv6yrz7pjccmwq2i4gcyaivnzts2h77a73g2diebf6gao4rmu", + "skill/valory/register_termination_abci/0.1.0": "bafybeiadiu5cjrwk5ceuiunzjbstwtzr3t6g4ptqoqg4vaxfgfgax2jd5e", + "skill/valory/test_abci/0.1.0": "bafybeibey5n6lviqytacqbm4jlu6qtkrz3edun45o7sbvdpluvdfolxo2q", + "agent/valory/abstract_abci/0.1.0": "bafybeicojdd6vpnsw3dyzbh3j7rs5ubihvd6y4tgrkbryrofqiyk54awki", + "agent/valory/counter/0.1.0": "bafybeidueagnkdtcw4ptf6wjhqw53qsclmgqubw4eovxqip4eqdwtcp7sa", + "agent/valory/counter_client/0.1.0": "bafybeiczbvqzoaltjd6pfwskniwqigubkarbshk2khtrwaz5vb5biwvw44", + "agent/valory/register_reset/0.1.0": "bafybeigrvrcrpy4zmifvej33zhhoxrvsxfsi2ebsic6a3kdl4hy6angmve", + "agent/valory/register_termination/0.1.0": "bafybeicjz22y4ih4oaouxijbcc2ycfxh2wg2ggs5svg4piiex6bk7222ce", + "agent/valory/registration_start_up/0.1.0": "bafybeihj222uo24chybhkdq6xmidw2eyng4ehnhzktg4x6lruienxw7sue", + "agent/valory/test_abci/0.1.0": "bafybeih6pwoej6yxng7imwwio3mge36wxrffxmpfz4llcnwspx5wmk2cvi", + "service/valory/counter/0.1.0": "bafybeiehjaxonhm45oagbuqdrc46vgxfzo75bx7kjnejw55qbwfzjmpyfi", + "service/valory/register_reset/0.1.0": "bafybeigbgqdhpilkxw7cprkdpxqhnakjd63howrdiwcpalsylpwrvvsvem", + "skill/valory/register_reset_recovery_abci/0.1.0": "bafybeihyfo3jxvsw6vuivdn72lobjq57k42wuwixt7qj6qrh2u5j534qgq", + "agent/valory/register_reset_recovery/0.1.0": "bafybeigwsw6eglzvfthyeyaviwvpjrbdlnma4d4fzbis7obgdnxeq5ew5q", + "contract/valory/multicall2/0.1.0": "bafybeif7c2sfjpjjueqevs5rmfpshlkbtrertdy2euvptecnzy2ioru7ue", + "skill/valory/slashing_abci/0.1.0": "bafybeievvfagzeod4ivbx7dmnmybrmodkzuav7kjz4wjjr3cagslsyh6oy", + "skill/valory/offend_abci/0.1.0": "bafybeifhczaajqghtwo754aukhy2uyollmksgxnofowem67wy5ie5ezmvm", + "skill/valory/offend_slash_abci/0.1.0": "bafybeidb6v5jmjmsiw5ydfoolzhl7w7clz2iazyuz5pikq7qmoq3fbxpne", + "agent/valory/offend_slash/0.1.0": "bafybeiafes7lwjd7zuvgjq6o2h752oi5wtbah6tgjstvymagb3xd6rtwse", + "contract/valory/erc20/0.1.0": "bafybeib7ctk3deleyxayrqvropewefr2muj4kcqe3t3wscak25bjmxnqwe", + "contract/valory/service_registry_token_utility/0.1.0": "bafybeifdia2y5546tvk6xzxeaqzf2n5n7dutj2hdzbgenxohaqhjtnjqm4" }, "third_party": { - "protocol/open_aea/signing/1.0.0": "bafybeibqlfmikg5hk4phzak6gqzhpkt6akckx7xppbp53mvwt6r73h7tk4", - "protocol/valory/acn/1.1.0": "bafybeignmc5uh3vgpuckljcj2tgg7hdqyytkm6m5b6v6mxtazdcvubibva", - "protocol/valory/http/1.0.0": "bafybeifyoio7nlh5zzyn5yz7krkou56l22to3cwg7gw5v5o3vxwklibhty", - "protocol/valory/ledger_api/1.0.0": "bafybeibo4bdtcrxi2suyzldwoetjar6pqfzm6vt5xal22ravkkcvdmtksi", - "protocol/valory/contract_api/1.0.0": "bafybeidv6wxpjyb2sdyibnmmum45et4zcla6tl63bnol6ztyoqvpl4spmy", - "connection/valory/http_client/0.23.0": "bafybeidykl4elwbcjkqn32wt5h4h7tlpeqovrcq3c5bcplt6nhpznhgczi", - "connection/valory/ledger/0.19.0": "bafybeicgfupeudtmvehbwziqfxiz6ztsxr5rxzvalzvsdsspzz73o5fzfi", - "connection/valory/p2p_libp2p_client/0.1.0": "bafybeidwcobzb7ut3efegoedad7jfckvt2n6prcmd4g7xnkm6hp6aafrva" + "protocol/open_aea/signing/1.0.0": "bafybeie7xyems76v5b4wc2lmaidcujizpxfzjnnwdeokmhje53g7ym25ii", + "protocol/valory/acn/1.1.0": "bafybeic2pxzfc3voxl2ejhcqyf2ehm4wm5gxvgx7bliloiqi2uppmq6weu", + "protocol/valory/http/1.0.0": "bafybeiejoqgv7finfxo3rcvvovrlj5ccrbgxodjq43uo26ylpowsa3llfe", + "protocol/valory/ledger_api/1.0.0": "bafybeige5agrztgzfevyglf7mb4o7pzfttmq4f6zi765y4g2zvftbyowru", + "protocol/valory/contract_api/1.0.0": "bafybeialhbjvwiwcnqq3ysxcyemobcbie7xza66gaofcvla5njezkvhcka", + "connection/valory/http_client/0.23.0": "bafybeiddrfvomrmgvh5yuv2coq7ci72wcdf663stayi3m5aawnj4srggce", + "connection/valory/ledger/0.19.0": "bafybeia47rr37ianvwsh77tjjpv3nwif5sywhhy2fbdshnz4a2icwln76a", + "connection/valory/p2p_libp2p_client/0.1.0": "bafybeihge56dn3xep2dzomu7rtvbgo4uc2qqh7ljl3fubqdi2lq44gs5lq" } } \ No newline at end of file diff --git a/packages/valory/agents/abstract_abci/aea-config.yaml b/packages/valory/agents/abstract_abci/aea-config.yaml index 12aa44304b..bc9126d5d2 100644 --- a/packages/valory/agents/abstract_abci/aea-config.yaml +++ b/packages/valory/agents/abstract_abci/aea-config.yaml @@ -11,14 +11,14 @@ fingerprint: tests/test_abstract_abci.py: bafybeic4hileugdjd6bwy4n5beqrjo5auwalz5twt3lyx6m62kb65nc6ca fingerprint_ignore_patterns: [] connections: -- valory/abci:0.1.0:bafybeih2l6ssf5ebkvgbag3hx2pd22shytszqavveib2e2s6rv4va5khv4 -- valory/p2p_libp2p_client:0.1.0:bafybeidwcobzb7ut3efegoedad7jfckvt2n6prcmd4g7xnkm6hp6aafrva +- valory/abci:0.1.0:bafybeih4lb2myvtypnfeji5jmgikmmazpgl3vyf5sy7oe66ji2zfjj6ily +- valory/p2p_libp2p_client:0.1.0:bafybeihge56dn3xep2dzomu7rtvbgo4uc2qqh7ljl3fubqdi2lq44gs5lq contracts: [] protocols: -- open_aea/signing:1.0.0:bafybeibqlfmikg5hk4phzak6gqzhpkt6akckx7xppbp53mvwt6r73h7tk4 -- valory/abci:0.1.0:bafybeig3dj5jhsowlvg3t73kgobf6xn4nka7rkttakdb2gwsg5bp7rt7q4 +- open_aea/signing:1.0.0:bafybeie7xyems76v5b4wc2lmaidcujizpxfzjnnwdeokmhje53g7ym25ii +- valory/abci:0.1.0:bafybeihmzlmmb4pdo3zkhg6ehuyaa4lhw7bfpclln2o2z7v3o6fcep26iu skills: -- valory/abstract_abci:0.1.0:bafybeifuclb6cikagtg2zn7dkjnnv3f7re2tfgzk6c4h3scgyzaaqeg55m +- valory/abstract_abci:0.1.0:bafybeial6drwstqlvuizgtouc4uqgxvutwryfu7yohondemd6bd7cw3jzm default_ledger: ethereum required_ledgers: - ethereum @@ -49,9 +49,9 @@ logging_config: propagate: true dependencies: open-aea-ledger-ethereum: - version: ==1.32.0 + version: ==1.43.0.post2 open-aea-test-autonomy: - version: ==0.10.2 + version: ==0.13.9.post1 default_connection: valory/abci:0.1.0 --- public_id: valory/abci:0.1.0 diff --git a/packages/valory/agents/counter/aea-config.yaml b/packages/valory/agents/counter/aea-config.yaml index 27b46f3717..26852eadfd 100644 --- a/packages/valory/agents/counter/aea-config.yaml +++ b/packages/valory/agents/counter/aea-config.yaml @@ -11,15 +11,15 @@ fingerprint: tests/test_counter.py: bafybeiafaruvutgm65f6wnc4u5z37cyiizuttbpelgs4bpmimnjyp5tnj4 fingerprint_ignore_patterns: [] connections: -- valory/abci:0.1.0:bafybeih2l6ssf5ebkvgbag3hx2pd22shytszqavveib2e2s6rv4va5khv4 -- valory/p2p_libp2p_client:0.1.0:bafybeidwcobzb7ut3efegoedad7jfckvt2n6prcmd4g7xnkm6hp6aafrva +- valory/abci:0.1.0:bafybeih4lb2myvtypnfeji5jmgikmmazpgl3vyf5sy7oe66ji2zfjj6ily +- valory/p2p_libp2p_client:0.1.0:bafybeihge56dn3xep2dzomu7rtvbgo4uc2qqh7ljl3fubqdi2lq44gs5lq contracts: [] protocols: -- open_aea/signing:1.0.0:bafybeibqlfmikg5hk4phzak6gqzhpkt6akckx7xppbp53mvwt6r73h7tk4 -- valory/abci:0.1.0:bafybeig3dj5jhsowlvg3t73kgobf6xn4nka7rkttakdb2gwsg5bp7rt7q4 +- open_aea/signing:1.0.0:bafybeie7xyems76v5b4wc2lmaidcujizpxfzjnnwdeokmhje53g7ym25ii +- valory/abci:0.1.0:bafybeihmzlmmb4pdo3zkhg6ehuyaa4lhw7bfpclln2o2z7v3o6fcep26iu skills: -- valory/abstract_abci:0.1.0:bafybeifuclb6cikagtg2zn7dkjnnv3f7re2tfgzk6c4h3scgyzaaqeg55m -- valory/counter:0.1.0:bafybeicodfeaolvkppkfoergy4vr5rc5nwntvadr2iebqjklawkvtfea2u +- valory/abstract_abci:0.1.0:bafybeial6drwstqlvuizgtouc4uqgxvutwryfu7yohondemd6bd7cw3jzm +- valory/counter:0.1.0:bafybeieunypccr354dbj7s5qcrxrwvkdci5wij5tn5nkqtk5twausre6zy default_ledger: ethereum required_ledgers: - ethereum @@ -50,9 +50,9 @@ logging_config: propagate: true dependencies: open-aea-ledger-ethereum: - version: ==1.32.0 + version: ==1.43.0.post2 open-aea-test-autonomy: - version: ==0.10.2 + version: ==0.13.9.post1 default_connection: null --- public_id: valory/abci:0.1.0 diff --git a/packages/valory/agents/counter_client/aea-config.yaml b/packages/valory/agents/counter_client/aea-config.yaml index c7f2962885..ebc2286956 100644 --- a/packages/valory/agents/counter_client/aea-config.yaml +++ b/packages/valory/agents/counter_client/aea-config.yaml @@ -8,14 +8,14 @@ fingerprint: README.md: bafybeig3kaj2bnhfnub3so6zz4e732jfhfawcyoqu2xitlfhp2x76anhlq fingerprint_ignore_patterns: [] connections: -- valory/http_client:0.23.0:bafybeidykl4elwbcjkqn32wt5h4h7tlpeqovrcq3c5bcplt6nhpznhgczi -- valory/p2p_libp2p_client:0.1.0:bafybeidwcobzb7ut3efegoedad7jfckvt2n6prcmd4g7xnkm6hp6aafrva +- valory/http_client:0.23.0:bafybeiddrfvomrmgvh5yuv2coq7ci72wcdf663stayi3m5aawnj4srggce +- valory/p2p_libp2p_client:0.1.0:bafybeihge56dn3xep2dzomu7rtvbgo4uc2qqh7ljl3fubqdi2lq44gs5lq contracts: [] protocols: -- open_aea/signing:1.0.0:bafybeibqlfmikg5hk4phzak6gqzhpkt6akckx7xppbp53mvwt6r73h7tk4 -- valory/http:1.0.0:bafybeifyoio7nlh5zzyn5yz7krkou56l22to3cwg7gw5v5o3vxwklibhty +- open_aea/signing:1.0.0:bafybeie7xyems76v5b4wc2lmaidcujizpxfzjnnwdeokmhje53g7ym25ii +- valory/http:1.0.0:bafybeiejoqgv7finfxo3rcvvovrlj5ccrbgxodjq43uo26ylpowsa3llfe skills: -- valory/counter_client:0.1.0:bafybeiaqdfulxamdshw7fykfkqvkpvjb5bnmhv7ffrjiwdi4ktiulklx6q +- valory/counter_client:0.1.0:bafybeignmckuvyuzvnwuhuor7oewy6yu7mpqht6ot46tznwujj5uu5ghc4 default_ledger: ethereum required_ledgers: - ethereum @@ -28,7 +28,7 @@ logging_config: version: 1 dependencies: open-aea-ledger-ethereum: - version: ==1.32.0 + version: ==1.43.0.post2 default_connection: null --- public_id: valory/p2p_libp2p_client:0.1.0 diff --git a/packages/valory/agents/hello_world/README.md b/packages/valory/agents/hello_world/README.md deleted file mode 100644 index 4e9cdde14c..0000000000 --- a/packages/valory/agents/hello_world/README.md +++ /dev/null @@ -1,4 +0,0 @@ -# Hello World ABCI Agent - -This agent uses the `abci` connection and the `hello_world_abci` skill -to demonstrate a Hello World ABCI implementation. diff --git a/packages/valory/agents/hello_world/aea-config.yaml b/packages/valory/agents/hello_world/aea-config.yaml deleted file mode 100644 index 8df7f9f267..0000000000 --- a/packages/valory/agents/hello_world/aea-config.yaml +++ /dev/null @@ -1,124 +0,0 @@ -agent_name: hello_world -author: valory -version: 0.1.0 -license: Apache-2.0 -description: Hello World ABCI example. -aea_version: '>=1.0.0, <2.0.0' -fingerprint: - README.md: bafybeifzdekpjcas6egpwxj24tir5ozzffmkq5ecyi6rw3i6fqfd763etu - __init__.py: bafybeiehvk4wlv2bcbplwc66owg4qdnisiihijq7iegcmjjxtz3dulnrgm - tests/__init__.py: bafybeiasj5kqyvalbnedototb6ooxfnro3vjmgscja2iccccotfjnd6cha - tests/test_hello_world.py: bafybeifbgqpywtwhk6n4wngdrrk3oujwqw3fsbk54gsw5sep3pkkgym2ue -fingerprint_ignore_patterns: [] -connections: -- valory/abci:0.1.0:bafybeih2l6ssf5ebkvgbag3hx2pd22shytszqavveib2e2s6rv4va5khv4 -- valory/http_client:0.23.0:bafybeidykl4elwbcjkqn32wt5h4h7tlpeqovrcq3c5bcplt6nhpznhgczi -- valory/ipfs:0.1.0:bafybeihubpyw2t3bwncz3l7jt4gf5xvfydwmob463vvgf3ikkhlwxakm3m -- valory/ledger:0.19.0:bafybeicgfupeudtmvehbwziqfxiz6ztsxr5rxzvalzvsdsspzz73o5fzfi -- valory/p2p_libp2p_client:0.1.0:bafybeidwcobzb7ut3efegoedad7jfckvt2n6prcmd4g7xnkm6hp6aafrva -contracts: [] -protocols: -- open_aea/signing:1.0.0:bafybeibqlfmikg5hk4phzak6gqzhpkt6akckx7xppbp53mvwt6r73h7tk4 -- valory/abci:0.1.0:bafybeig3dj5jhsowlvg3t73kgobf6xn4nka7rkttakdb2gwsg5bp7rt7q4 -- valory/http:1.0.0:bafybeifyoio7nlh5zzyn5yz7krkou56l22to3cwg7gw5v5o3vxwklibhty -- valory/ipfs:0.1.0:bafybeic72ncgqbzoz2guj4p4yjqulid7mv6yroeh65hxznloamoveeg7hq -skills: -- valory/abstract_abci:0.1.0:bafybeifuclb6cikagtg2zn7dkjnnv3f7re2tfgzk6c4h3scgyzaaqeg55m -- valory/abstract_round_abci:0.1.0:bafybeigiolzp3i6b3wwuau3yv2h5udqape3i7of73mlm2d6ud22irlkbme -- valory/hello_world_abci:0.1.0:bafybeiccrdfvkbrwawroglielcn2pf6vhhz7hoba2ya46ryd5zpmk4al5u -default_ledger: ethereum -required_ledgers: -- ethereum -default_routing: {} -connection_private_key_paths: {} -private_key_paths: {} -logging_config: - version: 1 - disable_existing_loggers: false - formatters: - standard: - format: '[%(asctime)s] [%(levelname)s] %(message)s' - handlers: - logfile: - class: logging.FileHandler - formatter: standard - filename: ${LOG_FILE:str:log.txt} - level: INFO - console: - class: logging.StreamHandler - formatter: standard - stream: ext://sys.stdout - loggers: - aea: - handlers: - - logfile - - console - propagate: true -dependencies: - open-aea-ledger-ethereum: - version: ==1.32.0 - open-aea-test-autonomy: - version: ==0.10.2 -default_connection: null ---- -public_id: valory/hello_world_abci:0.1.0 -type: skill -models: - benchmark_tool: - args: - log_dir: ${str:/benchmarks} - params: - args: - hello_world_message: ${str:HELLO_WORLD!} - service_registry_address: ${str:null} - share_tm_config_on_startup: ${bool:false} - on_chain_service_id: ${int:null} - setup: - all_participants: ${list:[]} - safe_contract_address: ${str:'0x0000000000000000000000000000000000000000'} - consensus_threshold: ${int:null} - tendermint_url: ${str:http://localhost:26657} - tendermint_com_url: ${str:http://localhost:8080} ---- -public_id: valory/abci:0.1.0 -type: connection -config: - target_skill_id: valory/hello_world_abci:0.1.0 - host: ${str:localhost} - port: ${int:26658} - use_tendermint: ${bool:false} ---- -public_id: valory/ledger:0.19.0 -type: connection -config: - ledger_apis: - ethereum: - address: ${str:http://localhost:8545} - chain_id: ${int:31337} - poa_chain: ${bool:false} - default_gas_price_strategy: ${str:eip1559} ---- -public_id: valory/p2p_libp2p_client:0.1.0 -type: connection -config: - nodes: - - uri: ${str:acn.staging.autonolas.tech:9005} - public_key: ${str:02d3a830c9d6ea1ae91936951430dee11f4662f33118b02190693be835359a9d77} - - uri: ${str:acn.staging.autonolas.tech:9006} - public_key: ${str:02e741c62d706e1dcf6986bf37fa74b98681bc32669623ac9ee6ff72488d4f59e8} -cert_requests: -- identifier: acn - ledger_id: ethereum - message_format: '{public_key}' - not_after: '2023-01-01' - not_before: '2022-01-01' - public_key: ${str:02d3a830c9d6ea1ae91936951430dee11f4662f33118b02190693be835359a9d77} - save_path: .certs/acn_cosmos_9005.txt -- identifier: acn - ledger_id: ethereum - message_format: '{public_key}' - not_after: '2023-01-01' - not_before: '2022-01-01' - public_key: ${str:02e741c62d706e1dcf6986bf37fa74b98681bc32669623ac9ee6ff72488d4f59e8} - save_path: .certs/acn_cosmos_9006.txt -is_abstract: true diff --git a/packages/valory/agents/hello_world/tests/test_hello_world.py b/packages/valory/agents/hello_world/tests/test_hello_world.py deleted file mode 100644 index 6210fe1293..0000000000 --- a/packages/valory/agents/hello_world/tests/test_hello_world.py +++ /dev/null @@ -1,187 +0,0 @@ -# -*- coding: utf-8 -*- -# ------------------------------------------------------------------------------ -# -# Copyright 2021-2023 Valory AG -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -# ------------------------------------------------------------------------------ - -"""End2end tests for the valory/hello_world skill.""" - -# pylint: skip-file - -from pathlib import Path -from typing import Tuple - -import pytest -from aea_test_autonomy.base_test_classes.agents import ( - BaseTestEnd2EndExecution, - RoundChecks, -) -from aea_test_autonomy.configurations import KEY_PAIRS -from aea_test_autonomy.fixture_helpers import ( # noqa: F401 - abci_host, - abci_port, - flask_tendermint, - ipfs_daemon, - ipfs_domain, - tendermint_port, -) - -from packages.valory.skills.hello_world_abci.behaviours import ( - CollectRandomnessBehaviour, - RegistrationBehaviour, - SelectKeeperBehaviour, -) -from packages.valory.skills.hello_world_abci.rounds import ( - CollectRandomnessRound, - PrintMessageRound, - RegistrationRound, - ResetAndPauseRound, - SelectKeeperRound, -) - - -HAPPY_PATH = ( - RoundChecks(RegistrationRound.auto_round_id()), - RoundChecks(PrintMessageRound.auto_round_id(), n_periods=3), - RoundChecks(CollectRandomnessRound.auto_round_id(), n_periods=3), - RoundChecks(SelectKeeperRound.auto_round_id(), n_periods=2), - RoundChecks(ResetAndPauseRound.auto_round_id(), n_periods=2), -) - -# strict check log messages of the happy path -STRICT_CHECK_STRINGS = ( - "Period end", - " in period 0 says: HELLO_WORLD!", - " in period 1 says: HELLO_WORLD!", - " in period 2 says: HELLO_WORLD!", - " in period 3 says: HELLO_WORLD!", -) - - -# normal execution -@pytest.mark.e2e -class BaseHelloWorldABCITest( - BaseTestEnd2EndExecution, -): - """Test the hello_world_abci skill with four agents.""" - - agent_package = "valory/hello_world:0.1.0" - skill_package = "valory/hello_world_abci:0.1.0" - wait_to_finish = 160 - happy_path = HAPPY_PATH - key_pairs = KEY_PAIRS - strict_check_strings: Tuple[str, ...] = STRICT_CHECK_STRINGS - package_registry_src_rel = Path(__file__).parent.parent.parent.parent.parent - ROUND_TIMEOUT_SECONDS = 30 - RESET_PAUSE_DURATION = 10 - - -@pytest.mark.usefixtures( - "flask_tendermint", "tendermint_port", "abci_host", "abci_port" -) -@pytest.mark.parametrize("nb_nodes", (1,)) -class TestHelloWorldABCISingleAgent(BaseHelloWorldABCITest): - """Test the hello_world_abci skill with only one agent.""" - - -@pytest.mark.usefixtures( - "flask_tendermint", "tendermint_port", "abci_host", "abci_port" -) -@pytest.mark.parametrize("nb_nodes", (2,)) -class TestHelloWorldABCITwoAgents(BaseHelloWorldABCITest): - """Test the hello_world_abci skill with two agents.""" - - -@pytest.mark.usefixtures( - "flask_tendermint", "tendermint_port", "abci_host", "abci_port" -) -@pytest.mark.parametrize("nb_nodes", (4,)) -class TestHelloWorldABCIFourAgents(BaseHelloWorldABCITest): - """Test the hello_world_abci skill with four agents.""" - - -# catchup test -class BaseHelloWorldABCITestCatchup(BaseHelloWorldABCITest): - """Test the hello_world_abci skill with catch up behaviour.""" - - stop_string = RegistrationBehaviour.auto_behaviour_id() - restart_after = 10 - n_terminal = 1 - - -# four behaviours and different stages of termination and restart -@pytest.mark.parametrize("nb_nodes", (4,)) -class TestHelloWorldABCIFourAgentsCatchupOnRegister(BaseHelloWorldABCITestCatchup): - """Test hello_world_abci skill with four agents; one restarting on `register`.""" - - stop_string = RegistrationBehaviour.auto_behaviour_id() - - -@pytest.mark.parametrize("nb_nodes", (4,)) -class TestHelloWorldABCIFourAgentsCatchupRetrieveRandomness( - BaseHelloWorldABCITestCatchup -): - """Test hello_world_abci skill with four agents; one restarting on `collect_randomness`.""" - - stop_string = CollectRandomnessBehaviour.auto_behaviour_id() - - -@pytest.mark.parametrize("nb_nodes", (4,)) -class TestHelloWorldABCIFourAgentsCatchupSelectKeeper(BaseHelloWorldABCITestCatchup): - """Test hello_world_abci skill with four agents; one restarting on `select_keeper`.""" - - stop_string = SelectKeeperBehaviour.auto_behaviour_id() - - -# multiple agents terminating and restarting -@pytest.mark.parametrize("nb_nodes", (4,)) -class TestHelloWorldABCIFourAgentsTwoAgentRestarting(BaseHelloWorldABCITestCatchup): - """Test the hello_world_abci skill with four agents and two restarting.""" - - n_terminal = 2 - - -@pytest.mark.skip(reason="https://github.com/valory-xyz/open-autonomy/issues/1709") -@pytest.mark.parametrize("nb_nodes", (1,)) -class TestHelloWorldABCISingleAgentGrpc( - BaseHelloWorldABCITest, -): - """Test that the hello_world_abci skill with only one agent.""" - - USE_GRPC = True - strict_check_strings = STRICT_CHECK_STRINGS + ("Starting gRPC server",) - - -@pytest.mark.skip(reason="https://github.com/valory-xyz/open-autonomy/issues/1709") -@pytest.mark.parametrize("nb_nodes", (2,)) -class TestHelloWorldABCITwoAgentsGrpc( - BaseHelloWorldABCITest, -): - """Test that the hello_world_abci skill with two agents.""" - - USE_GRPC = True - strict_check_strings = STRICT_CHECK_STRINGS + ("Starting gRPC server",) - - -@pytest.mark.skip(reason="https://github.com/valory-xyz/open-autonomy/issues/1709") -@pytest.mark.parametrize("nb_nodes", (4,)) -class TestHelloWorldABCIFourAgentsGrpc( - BaseHelloWorldABCITest, -): - """Test that the hello_world_abci skill with four agents.""" - - USE_GRPC = True - strict_check_strings = STRICT_CHECK_STRINGS + ("Starting gRPC server",) diff --git a/packages/valory/agents/offend_slash/README.md b/packages/valory/agents/offend_slash/README.md new file mode 100644 index 0000000000..5ec517b2f4 --- /dev/null +++ b/packages/valory/agents/offend_slash/README.md @@ -0,0 +1,3 @@ +# Offend Slash Agent + +This agent uses the registration, the offend, the slash, and the reset and pause skills to test the slashing feature. diff --git a/packages/valory/skills/hello_world_abci/tests/__init__.py b/packages/valory/agents/offend_slash/__init__.py similarity index 90% rename from packages/valory/skills/hello_world_abci/tests/__init__.py rename to packages/valory/agents/offend_slash/__init__.py index 1570dc3cf7..89a428c037 100644 --- a/packages/valory/skills/hello_world_abci/tests/__init__.py +++ b/packages/valory/agents/offend_slash/__init__.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- # ------------------------------------------------------------------------------ # -# Copyright 2021-2022 Valory AG +# Copyright 2023 Valory AG # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -17,4 +17,4 @@ # # ------------------------------------------------------------------------------ -"""Tests for valory/hello_world_abci skill.""" +"""An agent to test the slashing feature.""" diff --git a/packages/valory/agents/offend_slash/aea-config.yaml b/packages/valory/agents/offend_slash/aea-config.yaml new file mode 100644 index 0000000000..c2d8ea8fb9 --- /dev/null +++ b/packages/valory/agents/offend_slash/aea-config.yaml @@ -0,0 +1,125 @@ +agent_name: offend_slash +author: valory +version: 0.1.0 +license: Apache-2.0 +description: Offend and slash to test the slashing feature. +aea_version: '>=1.0.0, <2.0.0' +fingerprint: + README.md: bafybeibvdndrwbxlyljznpnv6rn7ks6e7sy4dfveb2vw7hqw3uuvrq64dm + __init__.py: bafybeihpqeerwvdztwaovdaas3lecjxztp7yectgjsqbk4phmpdjnww6fi + tests/__init__.py: bafybeic5zltt6wlvoegj2tfewe6qgr5f743lef4d6bkgvlqyfsnleiyb6y + tests/test_offend_slash.py: bafybeideqlz3vfssoylvesyr4oualignptsjsbiqlzgoskpd7ru6vosg4m +fingerprint_ignore_patterns: [] +connections: +- valory/abci:0.1.0:bafybeih4lb2myvtypnfeji5jmgikmmazpgl3vyf5sy7oe66ji2zfjj6ily +- valory/http_client:0.23.0:bafybeiddrfvomrmgvh5yuv2coq7ci72wcdf663stayi3m5aawnj4srggce +- valory/ipfs:0.1.0:bafybeigjtca6b5wwiobl37es3wllzt6ai3qef5gqxzfy5fmmc65jkbnec4 +- valory/ledger:0.19.0:bafybeia47rr37ianvwsh77tjjpv3nwif5sywhhy2fbdshnz4a2icwln76a +- valory/p2p_libp2p_client:0.1.0:bafybeihge56dn3xep2dzomu7rtvbgo4uc2qqh7ljl3fubqdi2lq44gs5lq +contracts: +- valory/gnosis_safe:0.1.0:bafybeiegkl6zrbvlbpwmoziw4hfkocjfqdqphkmpgow7ovsmv7bwa3f4pe +- valory/gnosis_safe_proxy_factory:0.1.0:bafybeiehjccqvhrcarhahhyyrshaifoipfqwvpxjucpucslp22l2wc3sl4 +- valory/service_registry:0.1.0:bafybeieeuruq7dp4b6souetv5ce7wlm52pw7vyrxuhqa7kuy5m3rwwxks4 +protocols: +- open_aea/signing:1.0.0:bafybeie7xyems76v5b4wc2lmaidcujizpxfzjnnwdeokmhje53g7ym25ii +- valory/abci:0.1.0:bafybeihmzlmmb4pdo3zkhg6ehuyaa4lhw7bfpclln2o2z7v3o6fcep26iu +- valory/acn:1.1.0:bafybeic2pxzfc3voxl2ejhcqyf2ehm4wm5gxvgx7bliloiqi2uppmq6weu +- valory/contract_api:1.0.0:bafybeialhbjvwiwcnqq3ysxcyemobcbie7xza66gaofcvla5njezkvhcka +- valory/http:1.0.0:bafybeiejoqgv7finfxo3rcvvovrlj5ccrbgxodjq43uo26ylpowsa3llfe +- valory/ipfs:0.1.0:bafybeiedxeismnx3k5ty4mvvhlqideixlhqmi5mtcki4lxqfa7uqh7p33u +- valory/ledger_api:1.0.0:bafybeige5agrztgzfevyglf7mb4o7pzfttmq4f6zi765y4g2zvftbyowru +- valory/tendermint:0.1.0:bafybeig6g6twajlwssfbfp5rlnu5mwzuu5kgak5cs4fich7rlkx6whesnu +skills: +- valory/abstract_abci:0.1.0:bafybeial6drwstqlvuizgtouc4uqgxvutwryfu7yohondemd6bd7cw3jzm +- valory/abstract_round_abci:0.1.0:bafybeicrzndcdbue34yxwwb4hmmdhgzw4owcdcdag3ifj6thpx5wie3dp4 +- valory/offend_abci:0.1.0:bafybeifhczaajqghtwo754aukhy2uyollmksgxnofowem67wy5ie5ezmvm +- valory/offend_slash_abci:0.1.0:bafybeidb6v5jmjmsiw5ydfoolzhl7w7clz2iazyuz5pikq7qmoq3fbxpne +- valory/registration_abci:0.1.0:bafybeihjlapvviakobxg7aa5qubgqoz6xurlhu7xxtnrg5ah3ag2qj626i +- valory/reset_pause_abci:0.1.0:bafybeibnwjcjx4lluf4cwb6es5peelu3gm7vrzlieygrzpbjlubxpvbvzy +- valory/slashing_abci:0.1.0:bafybeievvfagzeod4ivbx7dmnmybrmodkzuav7kjz4wjjr3cagslsyh6oy +- valory/transaction_settlement_abci:0.1.0:bafybeifpnkwgwpzz6uwrvfgurm26allr6shjfbp7bfbrxwy64sw3nf3fsa +default_ledger: ethereum +required_ledgers: +- ethereum +default_routing: {} +connection_private_key_paths: {} +private_key_paths: {} +logging_config: + version: 1 + disable_existing_loggers: false + formatters: + standard: + format: '[%(asctime)s] [%(levelname)s] %(message)s' + handlers: + logfile: + class: logging.FileHandler + formatter: standard + filename: ${LOG_FILE:str:log.txt} + level: INFO + console: + class: logging.StreamHandler + formatter: standard + stream: ext://sys.stdout + loggers: + aea: + handlers: + - logfile + - console + propagate: false +skill_exception_policy: stop_and_exit +dependencies: + open-aea-ledger-ethereum: + version: ==1.43.0.post2 + open-aea-test-autonomy: + version: ==0.13.9.post1 +default_connection: null +--- +public_id: valory/abci:0.1.0 +type: connection +config: + target_skill_id: valory/offend_slash_abci:0.1.0 + host: ${ABCI_HOST:str:localhost} + port: ${ABCI_PORT:int:26658} + use_tendermint: ${ABCI_USE_TENDERMINT:bool:false} +--- +public_id: valory/ledger:0.19.0 +type: connection +config: + ledger_apis: + ethereum: + address: ${CONNECTION_LEDGER_CONFIG_LEDGER_APIS_ETHEREUM_ADDRESS:str:http://localhost:8545} + chain_id: ${CONNECTION_LEDGER_CONFIG_LEDGER_APIS_ETHEREUM_CHAIN_ID:int:31337} +--- +public_id: valory/offend_slash_abci:0.1.0 +type: skill +models: + benchmark_tool: + args: + log_dir: ${str:/benchmarks} + params: + args: + tendermint_url: ${str:http://localhost:26657} + tendermint_com_url: ${str:http://localhost:8080} + use_termination: ${bool:true} + on_chain_service_id: ${int:1} + setup: + safe_contract_address: ${str:0x77b783e911F4398D75908Cc60C7138Bd1eFe35Fd} + consensus_threshold: ${int:null} + service_registry_address: ${str:0x998abeb3E57409262aE5b751f60747921B33613E} + share_tm_config_on_startup: ${bool:true} +--- +public_id: valory/p2p_libp2p_client:0.1.0 +type: connection +config: + nodes: + - uri: ${P2P_URI:str:localhost:11000} + public_key: ${P2P_PUBLIC_KEY:str:03c74dbfbe7bbc1b42429f78778017a3cd7eaf9d59d1634c9505a3f7c1a9350e71} +cert_requests: +- identifier: acn + ledger_id: ethereum + message_format: '{public_key}' + not_after: '2023-01-01' + not_before: '2022-01-01' + public_key: ${P2P_PUBLIC_KEY:str:03c74dbfbe7bbc1b42429f78778017a3cd7eaf9d59d1634c9505a3f7c1a9350e71} + save_path: .certs/acn_cosmos_11000.txt +is_abstract: false diff --git a/packages/valory/agents/hello_world/__init__.py b/packages/valory/agents/offend_slash/tests/__init__.py similarity index 91% rename from packages/valory/agents/hello_world/__init__.py rename to packages/valory/agents/offend_slash/tests/__init__.py index c138c857f5..43b922a219 100644 --- a/packages/valory/agents/hello_world/__init__.py +++ b/packages/valory/agents/offend_slash/tests/__init__.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- # ------------------------------------------------------------------------------ # -# Copyright 2022 Valory AG +# Copyright 2023 Valory AG # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -17,4 +17,4 @@ # # ------------------------------------------------------------------------------ -"""Module hello_world agent.""" +"""Tests for `offend_slash` agent.""" diff --git a/packages/valory/agents/offend_slash/tests/test_offend_slash.py b/packages/valory/agents/offend_slash/tests/test_offend_slash.py new file mode 100644 index 0000000000..579760fa4a --- /dev/null +++ b/packages/valory/agents/offend_slash/tests/test_offend_slash.py @@ -0,0 +1,127 @@ +# -*- coding: utf-8 -*- +# ------------------------------------------------------------------------------ +# +# Copyright 2023 Valory AG +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# ------------------------------------------------------------------------------ + +"""e2e tests for the `valory/offend_slash` skill.""" + +from pathlib import Path + +import pytest +from aea.configurations.data_types import PublicId +from aea_test_autonomy.base_test_classes.agents import ( + BaseTestEnd2End, + BaseTestEnd2EndExecution, + RoundChecks, +) +from aea_test_autonomy.fixture_helpers import ( # noqa: F401 pylint: disable=unused-import + UseACNNode, + UseRegistries, + abci_host, + abci_port, + acn_config, + acn_node, + flask_tendermint, + hardhat_addr, + hardhat_port, + ipfs_daemon, + ipfs_domain, + key_pairs, + registries_scope_class, + tendermint_port, +) + +from packages.valory.skills.offend_abci.rounds import OffendRound +from packages.valory.skills.registration_abci.rounds import RegistrationStartupRound +from packages.valory.skills.reset_pause_abci.rounds import ResetAndPauseRound +from packages.valory.skills.slashing_abci.rounds import StatusResetRound +from packages.valory.skills.transaction_settlement_abci.rounds import ( + RandomnessTransactionSubmissionRound, + ValidateTransactionRound, +) + + +NO_SLASHING_HAPPY_PATH = ( + RoundChecks(RegistrationStartupRound.auto_round_id()), + RoundChecks(OffendRound.auto_round_id(), n_periods=2), + RoundChecks(ResetAndPauseRound.auto_round_id(), n_periods=2), +) + +SLASHING_HAPPY_PATH = NO_SLASHING_HAPPY_PATH + ( + RoundChecks(ValidateTransactionRound.auto_round_id()), +) + +SLASHING_STRICT_CHECKS = ( + "The Event.SLASH_START event was produced, " + f"transitioning to `{RandomnessTransactionSubmissionRound.auto_round_id()}`", + f"Entered in the '{StatusResetRound.auto_round_id()}' round for period 0", + "The Event.SLASH_END event was produced. Switching back to the normal FSM.", +) + + +@pytest.mark.parametrize("nb_nodes", (4,)) +class SlashingE2E(UseRegistries, UseACNNode, BaseTestEnd2End): + """Test that slashing works right.""" + + package_registry_src_rel = Path(__file__).parents[4] + agent_package = "valory/offend_slash:0.1.0" + skill_package = "valory/offend_slash_abci:0.1.0" + wait_to_finish = 120 + _args_prefix = f"vendor.valory.skills.{PublicId.from_str(skill_package).name}.models.params.args" + + def __set_configs( # pylint: disable=unused-private-member + self, i: int, nb_agents: int + ) -> None: + """Set the current agent's config overrides.""" + super().__set_configs(i=i, nb_agents=nb_agents) + + self.set_config( + dotted_path=f"{self._args_prefix}.tendermint_p2p_url", + value=f"localhost:{self._tendermint_image.get_p2p_port(i=i)}", + type_="str", + ) + + +@pytest.mark.e2e +class TestSlashingThresholdUnmet(SlashingE2E, BaseTestEnd2EndExecution): + """Test that slashing works right.""" + + happy_path = NO_SLASHING_HAPPY_PATH + extra_configs = [ + { + "dotted_path": f"{SlashingE2E._args_prefix}.validator_downtime", + "value": True, + } + ] + + +@pytest.mark.e2e +class TestSlashing(SlashingE2E, BaseTestEnd2EndExecution): + """Test that slashing works right.""" + + happy_path = SLASHING_HAPPY_PATH + strict_check_strings = SLASHING_STRICT_CHECKS + extra_configs = [ + { + "dotted_path": f"{SlashingE2E._args_prefix}.validator_downtime", + "value": True, + }, + { + "dotted_path": f"{SlashingE2E._args_prefix}.num_double_signed", + "value": 1, + }, + ] diff --git a/packages/valory/agents/register_reset/aea-config.yaml b/packages/valory/agents/register_reset/aea-config.yaml index 60fc18e52b..b61cd6a95b 100644 --- a/packages/valory/agents/register_reset/aea-config.yaml +++ b/packages/valory/agents/register_reset/aea-config.yaml @@ -22,23 +22,23 @@ fingerprint: tests/test_register_reset.py: bafybeiecdipytoorhfpecbzd5pyx7e5zjpxsjc6yyqxezq2q6bhz7yuk7i fingerprint_ignore_patterns: [] connections: -- valory/abci:0.1.0:bafybeih2l6ssf5ebkvgbag3hx2pd22shytszqavveib2e2s6rv4va5khv4 -- valory/http_client:0.23.0:bafybeidykl4elwbcjkqn32wt5h4h7tlpeqovrcq3c5bcplt6nhpznhgczi -- valory/ipfs:0.1.0:bafybeihubpyw2t3bwncz3l7jt4gf5xvfydwmob463vvgf3ikkhlwxakm3m -- valory/ledger:0.19.0:bafybeicgfupeudtmvehbwziqfxiz6ztsxr5rxzvalzvsdsspzz73o5fzfi -- valory/p2p_libp2p_client:0.1.0:bafybeidwcobzb7ut3efegoedad7jfckvt2n6prcmd4g7xnkm6hp6aafrva +- valory/abci:0.1.0:bafybeih4lb2myvtypnfeji5jmgikmmazpgl3vyf5sy7oe66ji2zfjj6ily +- valory/http_client:0.23.0:bafybeiddrfvomrmgvh5yuv2coq7ci72wcdf663stayi3m5aawnj4srggce +- valory/ipfs:0.1.0:bafybeigjtca6b5wwiobl37es3wllzt6ai3qef5gqxzfy5fmmc65jkbnec4 +- valory/ledger:0.19.0:bafybeia47rr37ianvwsh77tjjpv3nwif5sywhhy2fbdshnz4a2icwln76a +- valory/p2p_libp2p_client:0.1.0:bafybeihge56dn3xep2dzomu7rtvbgo4uc2qqh7ljl3fubqdi2lq44gs5lq contracts: [] protocols: -- open_aea/signing:1.0.0:bafybeibqlfmikg5hk4phzak6gqzhpkt6akckx7xppbp53mvwt6r73h7tk4 -- valory/abci:0.1.0:bafybeig3dj5jhsowlvg3t73kgobf6xn4nka7rkttakdb2gwsg5bp7rt7q4 -- valory/http:1.0.0:bafybeifyoio7nlh5zzyn5yz7krkou56l22to3cwg7gw5v5o3vxwklibhty -- valory/ipfs:0.1.0:bafybeic72ncgqbzoz2guj4p4yjqulid7mv6yroeh65hxznloamoveeg7hq +- open_aea/signing:1.0.0:bafybeie7xyems76v5b4wc2lmaidcujizpxfzjnnwdeokmhje53g7ym25ii +- valory/abci:0.1.0:bafybeihmzlmmb4pdo3zkhg6ehuyaa4lhw7bfpclln2o2z7v3o6fcep26iu +- valory/http:1.0.0:bafybeiejoqgv7finfxo3rcvvovrlj5ccrbgxodjq43uo26ylpowsa3llfe +- valory/ipfs:0.1.0:bafybeiedxeismnx3k5ty4mvvhlqideixlhqmi5mtcki4lxqfa7uqh7p33u skills: -- valory/abstract_abci:0.1.0:bafybeifuclb6cikagtg2zn7dkjnnv3f7re2tfgzk6c4h3scgyzaaqeg55m -- valory/abstract_round_abci:0.1.0:bafybeigiolzp3i6b3wwuau3yv2h5udqape3i7of73mlm2d6ud22irlkbme -- valory/register_reset_abci:0.1.0:bafybeigvyiefdckrxjz67nxwswj73y7dbpj674bca4zd27gdcs6lcy2fku -- valory/registration_abci:0.1.0:bafybeigjzfdhhu6ody2qo5v2xjobafujnodklia4zw6bkkhahxtjfo3wby -- valory/reset_pause_abci:0.1.0:bafybeieeux3rdlcwgjbdfrluvkhqv26qdparre6pabatietw7juklljil4 +- valory/abstract_abci:0.1.0:bafybeial6drwstqlvuizgtouc4uqgxvutwryfu7yohondemd6bd7cw3jzm +- valory/abstract_round_abci:0.1.0:bafybeicrzndcdbue34yxwwb4hmmdhgzw4owcdcdag3ifj6thpx5wie3dp4 +- valory/register_reset_abci:0.1.0:bafybeihqsxv6yrz7pjccmwq2i4gcyaivnzts2h77a73g2diebf6gao4rmu +- valory/registration_abci:0.1.0:bafybeihjlapvviakobxg7aa5qubgqoz6xurlhu7xxtnrg5ah3ag2qj626i +- valory/reset_pause_abci:0.1.0:bafybeibnwjcjx4lluf4cwb6es5peelu3gm7vrzlieygrzpbjlubxpvbvzy default_ledger: ethereum required_ledgers: - ethereum @@ -69,9 +69,9 @@ logging_config: propagate: true dependencies: open-aea-ledger-ethereum: - version: ==1.32.0 + version: ==1.43.0.post2 open-aea-test-autonomy: - version: ==0.10.2 + version: ==0.13.9.post1 default_connection: null --- public_id: valory/abci:0.1.0 diff --git a/packages/valory/agents/register_reset_recovery/aea-config.yaml b/packages/valory/agents/register_reset_recovery/aea-config.yaml index b065541931..c1e206235a 100644 --- a/packages/valory/agents/register_reset_recovery/aea-config.yaml +++ b/packages/valory/agents/register_reset_recovery/aea-config.yaml @@ -12,22 +12,22 @@ fingerprint: tests/test_register_reset_recovery.py: bafybeiajrzfeqcdvapjhdjggyxya2g3gdxboodpagld6uyclrsrfsiri7u fingerprint_ignore_patterns: [] connections: -- valory/abci:0.1.0:bafybeih2l6ssf5ebkvgbag3hx2pd22shytszqavveib2e2s6rv4va5khv4 -- valory/http_client:0.23.0:bafybeidykl4elwbcjkqn32wt5h4h7tlpeqovrcq3c5bcplt6nhpznhgczi -- valory/ipfs:0.1.0:bafybeihubpyw2t3bwncz3l7jt4gf5xvfydwmob463vvgf3ikkhlwxakm3m -- valory/ledger:0.19.0:bafybeicgfupeudtmvehbwziqfxiz6ztsxr5rxzvalzvsdsspzz73o5fzfi -- valory/p2p_libp2p_client:0.1.0:bafybeidwcobzb7ut3efegoedad7jfckvt2n6prcmd4g7xnkm6hp6aafrva +- valory/abci:0.1.0:bafybeih4lb2myvtypnfeji5jmgikmmazpgl3vyf5sy7oe66ji2zfjj6ily +- valory/http_client:0.23.0:bafybeiddrfvomrmgvh5yuv2coq7ci72wcdf663stayi3m5aawnj4srggce +- valory/ipfs:0.1.0:bafybeigjtca6b5wwiobl37es3wllzt6ai3qef5gqxzfy5fmmc65jkbnec4 +- valory/ledger:0.19.0:bafybeia47rr37ianvwsh77tjjpv3nwif5sywhhy2fbdshnz4a2icwln76a +- valory/p2p_libp2p_client:0.1.0:bafybeihge56dn3xep2dzomu7rtvbgo4uc2qqh7ljl3fubqdi2lq44gs5lq contracts: [] protocols: -- open_aea/signing:1.0.0:bafybeibqlfmikg5hk4phzak6gqzhpkt6akckx7xppbp53mvwt6r73h7tk4 -- valory/abci:0.1.0:bafybeig3dj5jhsowlvg3t73kgobf6xn4nka7rkttakdb2gwsg5bp7rt7q4 -- valory/http:1.0.0:bafybeifyoio7nlh5zzyn5yz7krkou56l22to3cwg7gw5v5o3vxwklibhty -- valory/ipfs:0.1.0:bafybeic72ncgqbzoz2guj4p4yjqulid7mv6yroeh65hxznloamoveeg7hq +- open_aea/signing:1.0.0:bafybeie7xyems76v5b4wc2lmaidcujizpxfzjnnwdeokmhje53g7ym25ii +- valory/abci:0.1.0:bafybeihmzlmmb4pdo3zkhg6ehuyaa4lhw7bfpclln2o2z7v3o6fcep26iu +- valory/http:1.0.0:bafybeiejoqgv7finfxo3rcvvovrlj5ccrbgxodjq43uo26ylpowsa3llfe +- valory/ipfs:0.1.0:bafybeiedxeismnx3k5ty4mvvhlqideixlhqmi5mtcki4lxqfa7uqh7p33u skills: -- valory/abstract_abci:0.1.0:bafybeifuclb6cikagtg2zn7dkjnnv3f7re2tfgzk6c4h3scgyzaaqeg55m -- valory/abstract_round_abci:0.1.0:bafybeigiolzp3i6b3wwuau3yv2h5udqape3i7of73mlm2d6ud22irlkbme -- valory/register_reset_recovery_abci:0.1.0:bafybeiaw6cregh6whu2wbwoh2r7j6z5fzp4gdvxqw3dqhjzgmtqwutm5re -- valory/registration_abci:0.1.0:bafybeigjzfdhhu6ody2qo5v2xjobafujnodklia4zw6bkkhahxtjfo3wby +- valory/abstract_abci:0.1.0:bafybeial6drwstqlvuizgtouc4uqgxvutwryfu7yohondemd6bd7cw3jzm +- valory/abstract_round_abci:0.1.0:bafybeicrzndcdbue34yxwwb4hmmdhgzw4owcdcdag3ifj6thpx5wie3dp4 +- valory/register_reset_recovery_abci:0.1.0:bafybeihyfo3jxvsw6vuivdn72lobjq57k42wuwixt7qj6qrh2u5j534qgq +- valory/registration_abci:0.1.0:bafybeihjlapvviakobxg7aa5qubgqoz6xurlhu7xxtnrg5ah3ag2qj626i default_ledger: ethereum required_ledgers: - ethereum @@ -59,11 +59,12 @@ logging_config: propagate: true dependencies: open-aea-ledger-cosmos: - version: ==1.32.0 + version: ==1.43.0.post2 open-aea-ledger-ethereum: - version: ==1.32.0 + version: ==1.43.0.post2 open-aea-test-autonomy: - version: ==0.5.0 + version: ==0.13.9.post1 +skill_exception_policy: stop_and_exit default_connection: null --- public_id: valory/abci:0.1.0 diff --git a/packages/valory/agents/register_termination/aea-config.yaml b/packages/valory/agents/register_termination/aea-config.yaml index 8ba742b859..9998f0c415 100644 --- a/packages/valory/agents/register_termination/aea-config.yaml +++ b/packages/valory/agents/register_termination/aea-config.yaml @@ -8,37 +8,37 @@ fingerprint: README.md: bafybeiamp5k2dtww2rxaxu4kqsi3yon6mhofezlgcyzrialt2rnigkk43y __init__.py: bafybeihgxrmmp63exxkdmvlu565kehvuucg4iivnejwutaehb2p7xzxu4q tests/__init__.py: bafybeiftvheymtbp6iilmx7dceh46hplfxa3lss4xghz623gdon7jhpidi - tests/base.py: bafybeicly6lcxa32zjgfnvscfcgnzgiq5bfpvwfhrwx2dl2d4fhzxublle + tests/base.py: bafybeiglef3kgn5mppmqan2awzpheezcme3oz4rgtkiesusvaogwlwnyse tests/test_register_reset.py: bafybeieaeelbyrorts3akgsu7xp27jdsv5u7r4psatdxph2agvpym7em6m fingerprint_ignore_patterns: [] connections: -- valory/abci:0.1.0:bafybeih2l6ssf5ebkvgbag3hx2pd22shytszqavveib2e2s6rv4va5khv4 -- valory/http_client:0.23.0:bafybeidykl4elwbcjkqn32wt5h4h7tlpeqovrcq3c5bcplt6nhpznhgczi -- valory/ipfs:0.1.0:bafybeihubpyw2t3bwncz3l7jt4gf5xvfydwmob463vvgf3ikkhlwxakm3m -- valory/ledger:0.19.0:bafybeicgfupeudtmvehbwziqfxiz6ztsxr5rxzvalzvsdsspzz73o5fzfi -- valory/p2p_libp2p_client:0.1.0:bafybeidwcobzb7ut3efegoedad7jfckvt2n6prcmd4g7xnkm6hp6aafrva +- valory/abci:0.1.0:bafybeih4lb2myvtypnfeji5jmgikmmazpgl3vyf5sy7oe66ji2zfjj6ily +- valory/http_client:0.23.0:bafybeiddrfvomrmgvh5yuv2coq7ci72wcdf663stayi3m5aawnj4srggce +- valory/ipfs:0.1.0:bafybeigjtca6b5wwiobl37es3wllzt6ai3qef5gqxzfy5fmmc65jkbnec4 +- valory/ledger:0.19.0:bafybeia47rr37ianvwsh77tjjpv3nwif5sywhhy2fbdshnz4a2icwln76a +- valory/p2p_libp2p_client:0.1.0:bafybeihge56dn3xep2dzomu7rtvbgo4uc2qqh7ljl3fubqdi2lq44gs5lq contracts: -- valory/gnosis_safe:0.1.0:bafybeifvqalsuyetul3ypuolxvxzi5ffxoqdbqpfl3jadqjachsw7qfs74 -- valory/gnosis_safe_proxy_factory:0.1.0:bafybeierle6peb4a5cw3tncgondwhgesomzg7tedkb5cuos2zm462asbdi -- valory/multisend:0.1.0:bafybeigjywkl7hydjsrkogob3xebj2ifhqwmfhhxoeyrndzhhxi5u6amey -- valory/service_registry:0.1.0:bafybeiatzikdgcjteti6xeid4bvofszuavxb4fnczx33lcsvlaui4wpwua +- valory/gnosis_safe:0.1.0:bafybeiegkl6zrbvlbpwmoziw4hfkocjfqdqphkmpgow7ovsmv7bwa3f4pe +- valory/gnosis_safe_proxy_factory:0.1.0:bafybeiehjccqvhrcarhahhyyrshaifoipfqwvpxjucpucslp22l2wc3sl4 +- valory/multisend:0.1.0:bafybeig5byt5urg2d2bsecufxe5ql7f4mezg3mekfleeh32nmuusx66p4y +- valory/service_registry:0.1.0:bafybeieeuruq7dp4b6souetv5ce7wlm52pw7vyrxuhqa7kuy5m3rwwxks4 protocols: -- open_aea/signing:1.0.0:bafybeibqlfmikg5hk4phzak6gqzhpkt6akckx7xppbp53mvwt6r73h7tk4 -- valory/abci:0.1.0:bafybeig3dj5jhsowlvg3t73kgobf6xn4nka7rkttakdb2gwsg5bp7rt7q4 -- valory/acn:1.1.0:bafybeignmc5uh3vgpuckljcj2tgg7hdqyytkm6m5b6v6mxtazdcvubibva -- valory/contract_api:1.0.0:bafybeidv6wxpjyb2sdyibnmmum45et4zcla6tl63bnol6ztyoqvpl4spmy -- valory/http:1.0.0:bafybeifyoio7nlh5zzyn5yz7krkou56l22to3cwg7gw5v5o3vxwklibhty -- valory/ipfs:0.1.0:bafybeic72ncgqbzoz2guj4p4yjqulid7mv6yroeh65hxznloamoveeg7hq -- valory/ledger_api:1.0.0:bafybeibo4bdtcrxi2suyzldwoetjar6pqfzm6vt5xal22ravkkcvdmtksi -- valory/tendermint:0.1.0:bafybeicusvezoqlmyt6iqomcbwaz3xkhk2qf3d56q5zprmj3xdxfy64k54 +- open_aea/signing:1.0.0:bafybeie7xyems76v5b4wc2lmaidcujizpxfzjnnwdeokmhje53g7ym25ii +- valory/abci:0.1.0:bafybeihmzlmmb4pdo3zkhg6ehuyaa4lhw7bfpclln2o2z7v3o6fcep26iu +- valory/acn:1.1.0:bafybeic2pxzfc3voxl2ejhcqyf2ehm4wm5gxvgx7bliloiqi2uppmq6weu +- valory/contract_api:1.0.0:bafybeialhbjvwiwcnqq3ysxcyemobcbie7xza66gaofcvla5njezkvhcka +- valory/http:1.0.0:bafybeiejoqgv7finfxo3rcvvovrlj5ccrbgxodjq43uo26ylpowsa3llfe +- valory/ipfs:0.1.0:bafybeiedxeismnx3k5ty4mvvhlqideixlhqmi5mtcki4lxqfa7uqh7p33u +- valory/ledger_api:1.0.0:bafybeige5agrztgzfevyglf7mb4o7pzfttmq4f6zi765y4g2zvftbyowru +- valory/tendermint:0.1.0:bafybeig6g6twajlwssfbfp5rlnu5mwzuu5kgak5cs4fich7rlkx6whesnu skills: -- valory/abstract_abci:0.1.0:bafybeifuclb6cikagtg2zn7dkjnnv3f7re2tfgzk6c4h3scgyzaaqeg55m -- valory/abstract_round_abci:0.1.0:bafybeigiolzp3i6b3wwuau3yv2h5udqape3i7of73mlm2d6ud22irlkbme -- valory/register_termination_abci:0.1.0:bafybeidv74qpb5k6p5l3fn7qf4bo5o44dx6xfyj2i53rkazq6veyzeos5e -- valory/registration_abci:0.1.0:bafybeigjzfdhhu6ody2qo5v2xjobafujnodklia4zw6bkkhahxtjfo3wby -- valory/reset_pause_abci:0.1.0:bafybeieeux3rdlcwgjbdfrluvkhqv26qdparre6pabatietw7juklljil4 -- valory/termination_abci:0.1.0:bafybeifkl4ab6dnvtsaefe56dbzshmp5mozn7exwcaj2a3wjeq7u3hpezm -- valory/transaction_settlement_abci:0.1.0:bafybeifsz2ll7gmy6vmx34t6q5bdv6zzwp5zrehr6di6v3thcpc3sztkta +- valory/abstract_abci:0.1.0:bafybeial6drwstqlvuizgtouc4uqgxvutwryfu7yohondemd6bd7cw3jzm +- valory/abstract_round_abci:0.1.0:bafybeicrzndcdbue34yxwwb4hmmdhgzw4owcdcdag3ifj6thpx5wie3dp4 +- valory/register_termination_abci:0.1.0:bafybeiadiu5cjrwk5ceuiunzjbstwtzr3t6g4ptqoqg4vaxfgfgax2jd5e +- valory/registration_abci:0.1.0:bafybeihjlapvviakobxg7aa5qubgqoz6xurlhu7xxtnrg5ah3ag2qj626i +- valory/reset_pause_abci:0.1.0:bafybeibnwjcjx4lluf4cwb6es5peelu3gm7vrzlieygrzpbjlubxpvbvzy +- valory/termination_abci:0.1.0:bafybeifdtxgldw33kwvsavcituzewwbr6iqfcsgk5qouqfhpwdrivyyyom +- valory/transaction_settlement_abci:0.1.0:bafybeifpnkwgwpzz6uwrvfgurm26allr6shjfbp7bfbrxwy64sw3nf3fsa default_ledger: ethereum required_ledgers: - ethereum @@ -69,9 +69,9 @@ logging_config: propagate: false dependencies: open-aea-ledger-ethereum: - version: ==1.32.0 + version: ==1.43.0.post2 open-aea-test-autonomy: - version: ==0.10.2 + version: ==0.13.9.post1 default_connection: null --- public_id: valory/abci:0.1.0 diff --git a/packages/valory/agents/register_termination/tests/base.py b/packages/valory/agents/register_termination/tests/base.py index c4e9ffd8b1..9041370153 100644 --- a/packages/valory/agents/register_termination/tests/base.py +++ b/packages/valory/agents/register_termination/tests/base.py @@ -85,8 +85,10 @@ def _send_service_termination_signal(self) -> None: """ instance = web3.Web3(web3.HTTPProvider(self.NETWORK_ENDPOINT)) zero_eth = Wei(0) - checksum_sender_address = instance.toChecksumAddress(self.SERVICE_OWNER_ADDRESS) - checksum_receiver_address = instance.toChecksumAddress( + checksum_sender_address = instance.to_checksum_address( + self.SERVICE_OWNER_ADDRESS + ) + checksum_receiver_address = instance.to_checksum_address( self.SAFE_CONTRACT_ADDRESS ) @@ -97,9 +99,9 @@ def _send_service_termination_signal(self) -> None: "gas": 100000, "chainId": self.CHAIN_ID, "gasPrice": instance.eth.gas_price, - "nonce": instance.eth.getTransactionCount(checksum_sender_address), + "nonce": instance.eth.get_transaction_count(checksum_sender_address), } - signed_tx = instance.eth.account.signTransaction( + signed_tx = instance.eth.account.sign_transaction( raw_tx, private_key=self.SERVICE_OWNER_PK ) instance.eth.send_raw_transaction(signed_tx.rawTransaction) diff --git a/packages/valory/agents/registration_start_up/aea-config.yaml b/packages/valory/agents/registration_start_up/aea-config.yaml index 950ab483b3..e9dc13633d 100644 --- a/packages/valory/agents/registration_start_up/aea-config.yaml +++ b/packages/valory/agents/registration_start_up/aea-config.yaml @@ -11,26 +11,26 @@ fingerprint: tests/test_registration.py: bafybeickkytuflqwxg4y6n5bcnlxwnuutxsunan5ubvy7rj3y3me3ohtwi fingerprint_ignore_patterns: [] connections: -- valory/abci:0.1.0:bafybeih2l6ssf5ebkvgbag3hx2pd22shytszqavveib2e2s6rv4va5khv4 -- valory/http_client:0.23.0:bafybeidykl4elwbcjkqn32wt5h4h7tlpeqovrcq3c5bcplt6nhpznhgczi -- valory/ipfs:0.1.0:bafybeihubpyw2t3bwncz3l7jt4gf5xvfydwmob463vvgf3ikkhlwxakm3m -- valory/ledger:0.19.0:bafybeicgfupeudtmvehbwziqfxiz6ztsxr5rxzvalzvsdsspzz73o5fzfi -- valory/p2p_libp2p_client:0.1.0:bafybeidwcobzb7ut3efegoedad7jfckvt2n6prcmd4g7xnkm6hp6aafrva +- valory/abci:0.1.0:bafybeih4lb2myvtypnfeji5jmgikmmazpgl3vyf5sy7oe66ji2zfjj6ily +- valory/http_client:0.23.0:bafybeiddrfvomrmgvh5yuv2coq7ci72wcdf663stayi3m5aawnj4srggce +- valory/ipfs:0.1.0:bafybeigjtca6b5wwiobl37es3wllzt6ai3qef5gqxzfy5fmmc65jkbnec4 +- valory/ledger:0.19.0:bafybeia47rr37ianvwsh77tjjpv3nwif5sywhhy2fbdshnz4a2icwln76a +- valory/p2p_libp2p_client:0.1.0:bafybeihge56dn3xep2dzomu7rtvbgo4uc2qqh7ljl3fubqdi2lq44gs5lq contracts: -- valory/service_registry:0.1.0:bafybeiatzikdgcjteti6xeid4bvofszuavxb4fnczx33lcsvlaui4wpwua +- valory/service_registry:0.1.0:bafybeieeuruq7dp4b6souetv5ce7wlm52pw7vyrxuhqa7kuy5m3rwwxks4 protocols: -- open_aea/signing:1.0.0:bafybeibqlfmikg5hk4phzak6gqzhpkt6akckx7xppbp53mvwt6r73h7tk4 -- valory/abci:0.1.0:bafybeig3dj5jhsowlvg3t73kgobf6xn4nka7rkttakdb2gwsg5bp7rt7q4 -- valory/acn:1.1.0:bafybeignmc5uh3vgpuckljcj2tgg7hdqyytkm6m5b6v6mxtazdcvubibva -- valory/contract_api:1.0.0:bafybeidv6wxpjyb2sdyibnmmum45et4zcla6tl63bnol6ztyoqvpl4spmy -- valory/http:1.0.0:bafybeifyoio7nlh5zzyn5yz7krkou56l22to3cwg7gw5v5o3vxwklibhty -- valory/ipfs:0.1.0:bafybeic72ncgqbzoz2guj4p4yjqulid7mv6yroeh65hxznloamoveeg7hq -- valory/ledger_api:1.0.0:bafybeibo4bdtcrxi2suyzldwoetjar6pqfzm6vt5xal22ravkkcvdmtksi -- valory/tendermint:0.1.0:bafybeicusvezoqlmyt6iqomcbwaz3xkhk2qf3d56q5zprmj3xdxfy64k54 +- open_aea/signing:1.0.0:bafybeie7xyems76v5b4wc2lmaidcujizpxfzjnnwdeokmhje53g7ym25ii +- valory/abci:0.1.0:bafybeihmzlmmb4pdo3zkhg6ehuyaa4lhw7bfpclln2o2z7v3o6fcep26iu +- valory/acn:1.1.0:bafybeic2pxzfc3voxl2ejhcqyf2ehm4wm5gxvgx7bliloiqi2uppmq6weu +- valory/contract_api:1.0.0:bafybeialhbjvwiwcnqq3ysxcyemobcbie7xza66gaofcvla5njezkvhcka +- valory/http:1.0.0:bafybeiejoqgv7finfxo3rcvvovrlj5ccrbgxodjq43uo26ylpowsa3llfe +- valory/ipfs:0.1.0:bafybeiedxeismnx3k5ty4mvvhlqideixlhqmi5mtcki4lxqfa7uqh7p33u +- valory/ledger_api:1.0.0:bafybeige5agrztgzfevyglf7mb4o7pzfttmq4f6zi765y4g2zvftbyowru +- valory/tendermint:0.1.0:bafybeig6g6twajlwssfbfp5rlnu5mwzuu5kgak5cs4fich7rlkx6whesnu skills: -- valory/abstract_abci:0.1.0:bafybeifuclb6cikagtg2zn7dkjnnv3f7re2tfgzk6c4h3scgyzaaqeg55m -- valory/abstract_round_abci:0.1.0:bafybeigiolzp3i6b3wwuau3yv2h5udqape3i7of73mlm2d6ud22irlkbme -- valory/registration_abci:0.1.0:bafybeigjzfdhhu6ody2qo5v2xjobafujnodklia4zw6bkkhahxtjfo3wby +- valory/abstract_abci:0.1.0:bafybeial6drwstqlvuizgtouc4uqgxvutwryfu7yohondemd6bd7cw3jzm +- valory/abstract_round_abci:0.1.0:bafybeicrzndcdbue34yxwwb4hmmdhgzw4owcdcdag3ifj6thpx5wie3dp4 +- valory/registration_abci:0.1.0:bafybeihjlapvviakobxg7aa5qubgqoz6xurlhu7xxtnrg5ah3ag2qj626i default_ledger: ethereum required_ledgers: - ethereum @@ -62,11 +62,11 @@ logging_config: propagate: true dependencies: open-aea-ledger-cosmos: - version: ==1.32.0 + version: ==1.43.0.post2 open-aea-ledger-ethereum: - version: ==1.32.0 + version: ==1.43.0.post2 open-aea-test-autonomy: - version: ==0.10.2 + version: ==0.13.9.post1 skill_exception_policy: just_log connection_exception_policy: just_log default_connection: null diff --git a/packages/valory/agents/test_abci/aea-config.yaml b/packages/valory/agents/test_abci/aea-config.yaml index 1e5178a4bf..de46ce8231 100644 --- a/packages/valory/agents/test_abci/aea-config.yaml +++ b/packages/valory/agents/test_abci/aea-config.yaml @@ -8,23 +8,23 @@ fingerprint: README.md: bafybeib2s5p42rb4mbn7ag4jmjwutcm2mhvhb7q7vekxevr565crxkk6zy fingerprint_ignore_patterns: [] connections: -- valory/abci:0.1.0:bafybeih2l6ssf5ebkvgbag3hx2pd22shytszqavveib2e2s6rv4va5khv4 -- valory/http_client:0.23.0:bafybeidykl4elwbcjkqn32wt5h4h7tlpeqovrcq3c5bcplt6nhpznhgczi -- valory/ipfs:0.1.0:bafybeihubpyw2t3bwncz3l7jt4gf5xvfydwmob463vvgf3ikkhlwxakm3m -- valory/ledger:0.19.0:bafybeicgfupeudtmvehbwziqfxiz6ztsxr5rxzvalzvsdsspzz73o5fzfi -- valory/p2p_libp2p_client:0.1.0:bafybeidwcobzb7ut3efegoedad7jfckvt2n6prcmd4g7xnkm6hp6aafrva +- valory/abci:0.1.0:bafybeih4lb2myvtypnfeji5jmgikmmazpgl3vyf5sy7oe66ji2zfjj6ily +- valory/http_client:0.23.0:bafybeiddrfvomrmgvh5yuv2coq7ci72wcdf663stayi3m5aawnj4srggce +- valory/ipfs:0.1.0:bafybeigjtca6b5wwiobl37es3wllzt6ai3qef5gqxzfy5fmmc65jkbnec4 +- valory/ledger:0.19.0:bafybeia47rr37ianvwsh77tjjpv3nwif5sywhhy2fbdshnz4a2icwln76a +- valory/p2p_libp2p_client:0.1.0:bafybeihge56dn3xep2dzomu7rtvbgo4uc2qqh7ljl3fubqdi2lq44gs5lq contracts: [] protocols: -- open_aea/signing:1.0.0:bafybeibqlfmikg5hk4phzak6gqzhpkt6akckx7xppbp53mvwt6r73h7tk4 -- valory/abci:0.1.0:bafybeig3dj5jhsowlvg3t73kgobf6xn4nka7rkttakdb2gwsg5bp7rt7q4 -- valory/contract_api:1.0.0:bafybeidv6wxpjyb2sdyibnmmum45et4zcla6tl63bnol6ztyoqvpl4spmy -- valory/http:1.0.0:bafybeifyoio7nlh5zzyn5yz7krkou56l22to3cwg7gw5v5o3vxwklibhty -- valory/ipfs:0.1.0:bafybeic72ncgqbzoz2guj4p4yjqulid7mv6yroeh65hxznloamoveeg7hq -- valory/ledger_api:1.0.0:bafybeibo4bdtcrxi2suyzldwoetjar6pqfzm6vt5xal22ravkkcvdmtksi +- open_aea/signing:1.0.0:bafybeie7xyems76v5b4wc2lmaidcujizpxfzjnnwdeokmhje53g7ym25ii +- valory/abci:0.1.0:bafybeihmzlmmb4pdo3zkhg6ehuyaa4lhw7bfpclln2o2z7v3o6fcep26iu +- valory/contract_api:1.0.0:bafybeialhbjvwiwcnqq3ysxcyemobcbie7xza66gaofcvla5njezkvhcka +- valory/http:1.0.0:bafybeiejoqgv7finfxo3rcvvovrlj5ccrbgxodjq43uo26ylpowsa3llfe +- valory/ipfs:0.1.0:bafybeiedxeismnx3k5ty4mvvhlqideixlhqmi5mtcki4lxqfa7uqh7p33u +- valory/ledger_api:1.0.0:bafybeige5agrztgzfevyglf7mb4o7pzfttmq4f6zi765y4g2zvftbyowru skills: -- valory/abstract_abci:0.1.0:bafybeifuclb6cikagtg2zn7dkjnnv3f7re2tfgzk6c4h3scgyzaaqeg55m -- valory/abstract_round_abci:0.1.0:bafybeigiolzp3i6b3wwuau3yv2h5udqape3i7of73mlm2d6ud22irlkbme -- valory/test_abci:0.1.0:bafybeifbskwxg3vz6rl4vcgn4vdeyi5eqxewfnxv4o6ugeyilibmmimbn4 +- valory/abstract_abci:0.1.0:bafybeial6drwstqlvuizgtouc4uqgxvutwryfu7yohondemd6bd7cw3jzm +- valory/abstract_round_abci:0.1.0:bafybeicrzndcdbue34yxwwb4hmmdhgzw4owcdcdag3ifj6thpx5wie3dp4 +- valory/test_abci:0.1.0:bafybeibey5n6lviqytacqbm4jlu6qtkrz3edun45o7sbvdpluvdfolxo2q default_ledger: ethereum required_ledgers: - ethereum @@ -49,7 +49,7 @@ logging_config: propagate: true dependencies: open-aea-ledger-ethereum: - version: ==1.32.0 + version: ==1.43.0.post2 default_connection: null --- public_id: valory/abci:0.1.0 diff --git a/packages/valory/agents/test_ipfs/aea-config.yaml b/packages/valory/agents/test_ipfs/aea-config.yaml index ec5eebd34a..a0c4529905 100644 --- a/packages/valory/agents/test_ipfs/aea-config.yaml +++ b/packages/valory/agents/test_ipfs/aea-config.yaml @@ -11,26 +11,26 @@ fingerprint: tests/test_ipfs.py: bafybeib5fxk5gjuqyevp2rvzcjnyjfuwhfapappohc32xn7rnuu6lpwws4 fingerprint_ignore_patterns: [] connections: -- valory/abci:0.1.0:bafybeih2l6ssf5ebkvgbag3hx2pd22shytszqavveib2e2s6rv4va5khv4 -- valory/http_client:0.23.0:bafybeidykl4elwbcjkqn32wt5h4h7tlpeqovrcq3c5bcplt6nhpznhgczi -- valory/ipfs:0.1.0:bafybeihubpyw2t3bwncz3l7jt4gf5xvfydwmob463vvgf3ikkhlwxakm3m -- valory/ledger:0.19.0:bafybeicgfupeudtmvehbwziqfxiz6ztsxr5rxzvalzvsdsspzz73o5fzfi -- valory/p2p_libp2p_client:0.1.0:bafybeidwcobzb7ut3efegoedad7jfckvt2n6prcmd4g7xnkm6hp6aafrva +- valory/abci:0.1.0:bafybeih4lb2myvtypnfeji5jmgikmmazpgl3vyf5sy7oe66ji2zfjj6ily +- valory/http_client:0.23.0:bafybeiddrfvomrmgvh5yuv2coq7ci72wcdf663stayi3m5aawnj4srggce +- valory/ipfs:0.1.0:bafybeigjtca6b5wwiobl37es3wllzt6ai3qef5gqxzfy5fmmc65jkbnec4 +- valory/ledger:0.19.0:bafybeia47rr37ianvwsh77tjjpv3nwif5sywhhy2fbdshnz4a2icwln76a +- valory/p2p_libp2p_client:0.1.0:bafybeihge56dn3xep2dzomu7rtvbgo4uc2qqh7ljl3fubqdi2lq44gs5lq contracts: -- valory/service_registry:0.1.0:bafybeiatzikdgcjteti6xeid4bvofszuavxb4fnczx33lcsvlaui4wpwua +- valory/service_registry:0.1.0:bafybeieeuruq7dp4b6souetv5ce7wlm52pw7vyrxuhqa7kuy5m3rwwxks4 protocols: -- open_aea/signing:1.0.0:bafybeibqlfmikg5hk4phzak6gqzhpkt6akckx7xppbp53mvwt6r73h7tk4 -- valory/abci:0.1.0:bafybeig3dj5jhsowlvg3t73kgobf6xn4nka7rkttakdb2gwsg5bp7rt7q4 -- valory/acn:1.1.0:bafybeignmc5uh3vgpuckljcj2tgg7hdqyytkm6m5b6v6mxtazdcvubibva -- valory/contract_api:1.0.0:bafybeidv6wxpjyb2sdyibnmmum45et4zcla6tl63bnol6ztyoqvpl4spmy -- valory/http:1.0.0:bafybeifyoio7nlh5zzyn5yz7krkou56l22to3cwg7gw5v5o3vxwklibhty -- valory/ipfs:0.1.0:bafybeic72ncgqbzoz2guj4p4yjqulid7mv6yroeh65hxznloamoveeg7hq -- valory/ledger_api:1.0.0:bafybeibo4bdtcrxi2suyzldwoetjar6pqfzm6vt5xal22ravkkcvdmtksi -- valory/tendermint:0.1.0:bafybeicusvezoqlmyt6iqomcbwaz3xkhk2qf3d56q5zprmj3xdxfy64k54 +- open_aea/signing:1.0.0:bafybeie7xyems76v5b4wc2lmaidcujizpxfzjnnwdeokmhje53g7ym25ii +- valory/abci:0.1.0:bafybeihmzlmmb4pdo3zkhg6ehuyaa4lhw7bfpclln2o2z7v3o6fcep26iu +- valory/acn:1.1.0:bafybeic2pxzfc3voxl2ejhcqyf2ehm4wm5gxvgx7bliloiqi2uppmq6weu +- valory/contract_api:1.0.0:bafybeialhbjvwiwcnqq3ysxcyemobcbie7xza66gaofcvla5njezkvhcka +- valory/http:1.0.0:bafybeiejoqgv7finfxo3rcvvovrlj5ccrbgxodjq43uo26ylpowsa3llfe +- valory/ipfs:0.1.0:bafybeiedxeismnx3k5ty4mvvhlqideixlhqmi5mtcki4lxqfa7uqh7p33u +- valory/ledger_api:1.0.0:bafybeige5agrztgzfevyglf7mb4o7pzfttmq4f6zi765y4g2zvftbyowru +- valory/tendermint:0.1.0:bafybeig6g6twajlwssfbfp5rlnu5mwzuu5kgak5cs4fich7rlkx6whesnu skills: -- valory/abstract_abci:0.1.0:bafybeifuclb6cikagtg2zn7dkjnnv3f7re2tfgzk6c4h3scgyzaaqeg55m -- valory/abstract_round_abci:0.1.0:bafybeigiolzp3i6b3wwuau3yv2h5udqape3i7of73mlm2d6ud22irlkbme -- valory/test_ipfs_abci:0.1.0:bafybeic7ma7ipbzqno5hvv25aif6rqvmi7gb6vj2kpjbph7jrzidehxose +- valory/abstract_abci:0.1.0:bafybeial6drwstqlvuizgtouc4uqgxvutwryfu7yohondemd6bd7cw3jzm +- valory/abstract_round_abci:0.1.0:bafybeicrzndcdbue34yxwwb4hmmdhgzw4owcdcdag3ifj6thpx5wie3dp4 +- valory/test_ipfs_abci:0.1.0:bafybeigcwbshni7jt2wo7stkln2ku2pxa4z65kqy3xv7bucld63o5aftxe default_ledger: ethereum required_ledgers: - ethereum @@ -61,7 +61,7 @@ logging_config: propagate: true dependencies: open-aea-ledger-ethereum: - version: ==1.32.0 + version: ==1.43.0.post2 default_connection: null --- public_id: valory/abci:0.1.0 diff --git a/packages/valory/connections/abci/__init__.py b/packages/valory/connections/abci/__init__.py index cbe7b0abbb..106a847241 100644 --- a/packages/valory/connections/abci/__init__.py +++ b/packages/valory/connections/abci/__init__.py @@ -18,9 +18,3 @@ # ------------------------------------------------------------------------------ """Abci connection.""" # pragma: nocover -from hypothesis import settings - - -CI = "CI" # pragma: nocover - -settings.register_profile(CI, deadline=5000) # pragma: nocover diff --git a/packages/valory/connections/abci/connection.py b/packages/valory/connections/abci/connection.py index 30b8166811..9cdaa5ab9a 100644 --- a/packages/valory/connections/abci/connection.py +++ b/packages/valory/connections/abci/connection.py @@ -24,6 +24,7 @@ import platform import signal import subprocess # nosec +import sys from asyncio import AbstractEventLoop, AbstractServer, CancelledError, Task from io import BytesIO from logging import Logger @@ -1037,7 +1038,7 @@ async def send(self, envelope: Envelope) -> None: class StoppableThread( Thread, -): # pragma: no cover (covered via deployments/Dockerfiles/tendermint/tendermint.py) +): """Thread class with a stop() method.""" def __init__(self, *args: Any, **kwargs: Any) -> None: @@ -1054,7 +1055,7 @@ def stopped(self) -> bool: return self._stop_event.is_set() -class TendermintParams: # pylint: disable=too-few-public-methods # pragma: no cover (covered via deployments/Dockerfiles/tendermint/tendermint.py) +class TendermintParams: # pylint: disable=too-few-public-methods """Tendermint node parameters.""" def __init__( # pylint: disable=too-many-arguments @@ -1115,47 +1116,49 @@ def build_node_command(self, debug: bool = False) -> List[str]: ] if debug: cmd.append("--log_level=debug") - if self.home is not None: # pragma: nocover cmd += ["--home", self.home] return cmd @staticmethod - def get_node_command_kwargs(monitoring: bool = False) -> Dict: + def get_node_command_kwargs() -> Dict: """Get the node command kwargs""" kwargs = { "bufsize": 1, "universal_newlines": True, + "stdout": subprocess.PIPE, + "stderr": subprocess.STDOUT, } - - # Only redirect stdout and stderr if we're going to read - if monitoring: - kwargs["stdout"] = subprocess.PIPE - kwargs["stderr"] = subprocess.STDOUT - if platform.system() == "Windows": # pragma: nocover kwargs["creationflags"] = subprocess.CREATE_NEW_PROCESS_GROUP # type: ignore else: kwargs["preexec_fn"] = os.setsid # type: ignore - return kwargs class TendermintNode: """A class to manage a Tendermint node.""" - def __init__(self, params: TendermintParams, logger: Optional[Logger] = None): + def __init__( + self, + params: TendermintParams, + logger: Optional[Logger] = None, + write_to_log: bool = False, + ): """ Initialize a Tendermint node. :param params: the parameters. :param logger: the logger. + :param write_to_log: Write to log file. """ self.params = params self._process: Optional[subprocess.Popen] = None self._monitoring: Optional[StoppableThread] = None + self._stopping = False self.logger = logger or logging.getLogger() self.log_file = os.environ.get("LOG_FILE", DEFAULT_TENDERMINT_LOG_FILE) + self.write_to_log = write_to_log def _build_init_command(self) -> List[str]: """Build the 'init' command.""" @@ -1172,42 +1175,74 @@ def init(self) -> None: cmd = self._build_init_command() subprocess.call(cmd) # nosec - def start(self, start_monitoring: bool = False, debug: bool = False) -> None: - """Start a Tendermint node process.""" - self._start_tm_process(start_monitoring, debug) - if start_monitoring: - self._start_monitoring_thread() + def _monitor_tendermint_process( + self, + ) -> None: + """Check server status.""" + if self._monitoring is None: + raise ValueError("Monitoring is not running") + self.log("Monitoring thread started\n") + while not self._monitoring.stopped(): + try: + if self._process is not None and self._process.stdout is not None: + line = self._process.stdout.readline() + self.log(line) + for trigger in [ + # this occurs when we lose connection from the tm side + "RPC HTTP server stopped", + # whenever the node is stopped because of a closed connection + # from on any of the tendermint modules (abci, p2p, rpc, etc) + # we restart the node + "Stopping abci.socketClient for error: read message: EOF", + ]: + if self._monitoring.stopped(): + break + if line.find(trigger) >= 0: + self._stop_tm_process() + # we can only reach this step if monitoring was activated + # so we make sure that after reset the monitoring continues + self._start_tm_process() + self.log( + f"Restarted the HTTP RPC server, as a connection was dropped with message:\n\t\t {line}\n" + ) + except Exception as e: # pylint: disable=broad-except + self.log(f"Error!: {str(e)}") + self.log("Monitoring thread terminated\n") - def _start_tm_process(self, monitoring: bool = False, debug: bool = False) -> None: + def _start_tm_process(self, debug: bool = False) -> None: """Start a Tendermint node process.""" - - if self._process is not None: # pragma: nocover + if self._process is not None or self._stopping: # pragma: nocover return - cmd = self.params.build_node_command(debug) - kwargs = self.params.get_node_command_kwargs(monitoring) - - logging.info(f"Starting Tendermint: {cmd}") + kwargs = self.params.get_node_command_kwargs() + self.log(f"Starting Tendermint: {cmd}\n") self._process = ( subprocess.Popen( # nosec # pylint: disable=consider-using-with,W1509 cmd, **kwargs ) ) - - self.write_line("Tendermint process started\n") + self.log("Tendermint process started\n") def _start_monitoring_thread(self) -> None: """Start a monitoring thread.""" - self._monitoring = StoppableThread(target=self.check_server_status) + self._monitoring = StoppableThread(target=self._monitor_tendermint_process) self._monitoring.start() + def start(self, debug: bool = False) -> None: + """Start a Tendermint node process.""" + self._start_tm_process(debug) + self._start_monitoring_thread() + def _stop_tm_process(self) -> None: """Stop a Tendermint node process.""" - if self._process is None: + if self._process is None or self._stopping: return + self._stopping = True if platform.system() == "Windows": os.kill(self._process.pid, signal.CTRL_C_EVENT) # type: ignore # pylint: disable=no-member + if self._process is None: + return try: self._process.wait(timeout=5) except subprocess.TimeoutExpired: # nosec @@ -1215,13 +1250,16 @@ def _stop_tm_process(self) -> None: else: self._process.send_signal(signal.SIGTERM) self._process.wait(timeout=5) + if self._process is None: + return poll = self._process.poll() if poll is None: # pragma: nocover self._process.terminate() self._process.wait(3) + self._stopping = False self._process = None - self.write_line("Tendermint process stopped\n") + self.log("Tendermint process stopped\n") def _stop_monitoring_thread(self) -> None: """Stop a monitoring process.""" @@ -1231,8 +1269,25 @@ def _stop_monitoring_thread(self) -> None: def stop(self) -> None: """Stop a Tendermint node process.""" - self._stop_monitoring_thread() self._stop_tm_process() + self._stop_monitoring_thread() + + @staticmethod + def _write_to_console(line: str) -> None: + """Write line to console.""" + sys.stdout.write(str(line)) + sys.stdout.flush() + + def _write_to_file(self, line: str) -> None: + """Write line to console.""" + with open(self.log_file, "a", encoding=ENCODING) as file: + file.write(line) + + def log(self, line: str) -> None: + """Open and write a line to the log file.""" + self._write_to_console(line=line) + if self.write_to_log: + self._write_to_file(line=line) def prune_blocks(self) -> int: """Prune blocks from the Tendermint state""" @@ -1240,46 +1295,6 @@ def prune_blocks(self) -> int: ["tendermint", "--home", str(self.params.home), "unsafe-reset-all"] ) - def write_line(self, line: str) -> None: - """Open and write a line to the log file.""" - with open(self.log_file, "a", encoding=ENCODING) as file: - file.write(line) - - def check_server_status( - self, - ) -> None: - """Check server status.""" - if self._monitoring is None: - raise ValueError("Monitoring is not running") - self.write_line("Monitoring thread started\n") - while True: - try: - if self._monitoring.stopped(): - break # break from the loop immediately. - if self._process is not None and self._process.stdout is not None: - line = self._process.stdout.readline() - self.write_line(line) - for trigger in [ - # this occurs when we lose connection from the tm side - "RPC HTTP server stopped", - # whenever the node is stopped because of a closed connection - # from on any of the tendermint modules (abci, p2p, rpc, etc) - # we restart the node - "Stopping abci.socketClient for error: read message: EOF", - ]: - if line.find(trigger) >= 0: - self._stop_tm_process() - # we can only reach this step if monitoring was activated - # so we make sure that after reset the monitoring continues - monitoring = True - self._start_tm_process(monitoring) - self.write_line( - f"Restarted the HTTP RPC server, as a connection was dropped with message:\n\t\t {line}\n" - ) - except Exception as e: # pylint: disable=broad-except - self.write_line(f"Error!: {str(e)}") - self.write_line("Monitoring thread terminated\n") - def reset_genesis_file( self, genesis_time: str, initial_height: str, period_count: str ) -> None: diff --git a/packages/valory/connections/abci/connection.yaml b/packages/valory/connections/abci/connection.yaml index a260b3c76a..8d4789e36f 100644 --- a/packages/valory/connections/abci/connection.yaml +++ b/packages/valory/connections/abci/connection.yaml @@ -7,12 +7,12 @@ license: Apache-2.0 aea_version: '>=1.0.0, <2.0.0' fingerprint: Makefile: bafybeibdgarch56r46dfy7x7fouj52nbjpjs4fgtrd3prgtwelowyjan5i - __init__.py: bafybeiafpun3qgjw6zpiuq6jovo2taxkavw2gd7mn5yv73sh3uy5pea3o4 + __init__.py: bafybeic2m6f6j42cbfxz3jcwhju2dcbbdcw6xyc7mslq7uk2hwe6ctcugi check_dependencies.py: bafybeihmhemryyl2iacwwrqebr7us7wx4otvwbdbtckwkl5kxqopidyzwm - connection.py: bafybeig3e43a44isn6ixvu43vp5orpbauv6jkma7w3fn52jjw3mk5agh6u + connection.py: bafybeialq56ta7w6ikkzugtmb75n2buaujhzwtgpcf4fuj2nx6i2bhcodu dialogues.py: bafybeibpdsphu5vqjpieczrb3ulhqfcq4l73qnx6j3zhbz4dpunwegboxq gogoproto/__init__.py: bafybeifmpcbkrpygdt7uvhpq6gaxgskofpczxktoalp2cwyouay46drcke - gogoproto/gogo_pb2.py: bafybeih2nnsem7jmzljqgc4qptoaj2zlfbuyooqiymuvomwrzzavs26ufe + gogoproto/gogo_pb2.py: bafybeifdutphcruyva7lcngujrcmfsaycyodyfjbgwcrxthiouotl4fxpu protos/gogoproto/gogo.proto: bafybeieg7yu62cx25ssjgvjnsc2alececsgush6l5adpxuscaf6ksh6dou protos/tendermint/abci/types.proto: bafybeigimbf3rrfavl2o2jakr5c6dfm652lzxsddcmho7w5ytxo33sgrm4 protos/tendermint/crypto/keys.proto: bafybeiar5g76sw7wgiyvaczpfgmw2bqkuillti7lnibmmmenz5zdofm6xe @@ -24,30 +24,30 @@ fingerprint: readme.md: bafybeierlmc7t4dwpgc3sgmn5m5l3r4fwnwzbf6agna3igndsogk3iqlv4 scripts/genproto.py: bafybeicfgwktvlrzqwfbvbld6bor3qd2rcfcgmk5rzfcfl6oj3jrr2mequ tendermint/__init__.py: bafybeifayxyjcebekkn62sucyupfcuwzlj57kuiwafynpw4nrbocqxe6ya - tendermint/abci/types_pb2.py: bafybeif4im3bdtc6pvhcdrhhfydr2kzh3vuqez57fj43xqlrnm5yls2idm + tendermint/abci/types_pb2.py: bafybeidvvklivlllwprj2rh6un45apg773muyjrsq5momcihi2abxioqsi tendermint/abci/types_pb2_grpc.py: bafybeihmecy4uas7itftoaslrqvrjb3m2jewojuzxvie7pjzsrw5exnu6u - tendermint/crypto/keys_pb2.py: bafybeifo4ian5shlehmopaoew3oz5e7n3jkke2byviuzggkt2ctxyuutoi - tendermint/crypto/proof_pb2.py: bafybeicz5vfricor4iromt3phy5kelz27af4nnajada3emiyy7fwbyhsyu - tendermint/types/params_pb2.py: bafybeiap3oi5yr63za4yihkf7gmhh6acdu7a45swdcknu27wqzilmj3brq - tendermint/types/types_pb2.py: bafybeide3f3tmqiuxpiu2dmimd5sghphoqd4rka2pdnxvfaoawsfm2ejmu - tendermint/types/validator_pb2.py: bafybeihbukxnnvzbc2w75uln5qxyj3sle7euezbwo6pk65rbdznexgatbm - tendermint/version/types_pb2.py: bafybeiee7dx3fxa4vnuyosl6qps7z6guk3p627lan7owqjuq3rgjhfqnty - tendermint_decoder.py: bafybeidal3n3q4lka4zwbrt277lmlhht5nlxnpnmc4rwi6zb5halnksomu - tendermint_encoder.py: bafybeibzfssuon2i7omvpe6qmcrv62kje2rik36qm5m5jzeb4m6nu42z2i - tests/__init__.py: bafybeid67ezzjsfsukyqdjtlnd3ra5yy73jnobm4setddgagd3u4vqboyu - tests/helper.py: bafybeicdnny6bobjlmqzpvkyce7dxusa54xyo3ooyvzizlbsnz57scll4i + tendermint/crypto/keys_pb2.py: bafybeiamkizmrn7txfboyrqqdara7n6ix5pbfh4evc3xedeva65snmlfhe + tendermint/crypto/proof_pb2.py: bafybeie7zueijrsuzldcol7dkcd2udupbof6nm73zm6zzkkin6teauan2m + tendermint/types/params_pb2.py: bafybeifblynzqqhyuvwjzgz33izwi5fl6fqabyiuwspasdlkw32xhltxq4 + tendermint/types/types_pb2.py: bafybeiad3gl7a3o4aewrcxfg5qpmjgtpeobcvb5knjxofwo7jjiimeb4m4 + tendermint/types/validator_pb2.py: bafybeibdhuvir43t4he337ajwe6sk7suhzxgdxyk2i6neoonoxfjqtqd6q + tendermint/version/types_pb2.py: bafybeib7ucwdh2oqbprdjskfofjkidf3odpj34zwicckkze6esx2zlsdaq + tendermint_decoder.py: bafybeig3teywhof2vztwaiqj36nx5bv6fysxzmu7i5ewqxa2w7rdf3wa7i + tendermint_encoder.py: bafybeibpnofkac6jizpbezlo7rdsbijloovsuz5rjysshjrims7x44wxv4 + tests/__init__.py: bafybeiaca7l7u423yejqpbbkyvrkrhog2zqpmtbvrga6bjou3yogj4bina + tests/helper.py: bafybeidahgf7lfoachhqliysh6uxc3prjl3yweicay4tkjsqwkxt67lphu tests/test_abci.py: bafybeia4pw67do72gzc66kz23yzllnspbzqrtd5c5muqxhol27ipjjscxa - tests/test_abci_fuzz.py: bafybeicd7chwsit4mr6ypaeulkz7dsxyzv5mkmjw7fxxmey3xfxcq3cy2a + tests/test_abci_fuzz.py: bafybeiddeye3fbgefihbgdhqwwuv3dlseo6d5kt3jpixpq45bewm5dep2u tests/test_abci_spec.py: bafybeifacnizp2mryyb2j64iugnxn5rhtx7xr4emwbw5xcke6le6utpwhu tests/test_fuzz/__init__.py: bafybeiggaobawdxpx2j637ldmacq7r7tnyeygukmjuayodj3vytdyqsjze - tests/test_fuzz/base.py: bafybeihcup3o3pbyfk33bvhznxsedjzf4wnbuoa6h3czo34m4qqyss6ixq + tests/test_fuzz/base.py: bafybeifcv7r4dk7dfw726r3dy42s6mozb5yk4mmhml5i3hpu653odax7bq tests/test_fuzz/mock_node/__init__.py: bafybeibt3bm4l3wethryy564mzcbhqmnztsbko4c5bt5ila5ghq2e7vz7u tests/test_fuzz/mock_node/channels/__init__.py: bafybeifjjnlxtqd4pz76aq6w642n5d6pa635ehkhjxgzyjidakza27adja - tests/test_fuzz/mock_node/channels/base.py: bafybeiewnctbkmmnnqwsrlwy2rfaypmva7xuclgwzfuwwrua3xpqf43f54 - tests/test_fuzz/mock_node/channels/grpc_channel.py: bafybeid2na2emvcgvax46mghr6nb4cimtskp4phtvokuyt3pymsbiohjnq - tests/test_fuzz/mock_node/channels/tcp_channel.py: bafybeibxpapyxatsnfnzixemmdp7lfhyrugl2rlvp73tv3d7mjkdphbccu - tests/test_fuzz/mock_node/node.py: bafybeieyq4vbddnk5qnvwttmralv6soadz276rapembzjp5sbhcnmvaida - tests/test_fuzz/test_fuzz.py: bafybeigpgbo6afvhhkyh2yxv64awpnxbxyfaqp5fifgdsm5v7grbzjrk2i + tests/test_fuzz/mock_node/channels/base.py: bafybeicsirvtetuxnophhibjlzeos4bwtchhxr76v4k4ajsht6vrsqb5ni + tests/test_fuzz/mock_node/channels/grpc_channel.py: bafybeidita6lkds4urwrt3jwpou22js7ngruoof7kynuhkultdytx5taua + tests/test_fuzz/mock_node/channels/tcp_channel.py: bafybeiehlihhp7itiypkilugorwa2rytz2fm3awkm7vhti5p2v7fcvvajq + tests/test_fuzz/mock_node/node.py: bafybeiakzuvng5elaws6mv246o2nrjitdvjr7j5ltrhxscpezybbsyzh3i + tests/test_fuzz/test_fuzz.py: bafybeihfsayqmhajvhthvirxicd4swpe32u2gohe7sq5ixjuygico6wzge tests/test_tendermint_decoder.py: bafybeihogt3aopyln5newihm3rbiqimoc4aw6za2cngplnjnwatv6nakea tests/test_tendermint_encoder.py: bafybeigpun2ybwr5tu7b52his3b5apyrlmdytlgofcszbctsmmabo3sjg4 version.txt: bafybeifjb44fd7qve2ku62ythui6z4mvd4k7qkjomlcdnl3ymb3bnq6xee @@ -55,7 +55,7 @@ fingerprint_ignore_patterns: [] build_entrypoint: check_dependencies.py connections: [] protocols: -- valory/abci:0.1.0:bafybeig3dj5jhsowlvg3t73kgobf6xn4nka7rkttakdb2gwsg5bp7rt7q4 +- valory/abci:0.1.0:bafybeihmzlmmb4pdo3zkhg6ehuyaa4lhw7bfpclln2o2z7v3o6fcep26iu class_name: ABCIServerConnection config: host: 127.0.0.1 @@ -73,12 +73,12 @@ excluded_protocols: [] restricted_to_protocols: [] dependencies: grpcio: - version: ==1.43.0 + version: ==1.53.0 hypothesis: version: ==6.21.6 open-aea-test-autonomy: - version: ==0.10.2 + version: ==0.13.9.post1 protobuf: - version: <=3.20.1,>=3.20 + version: <4.25.0,>=4.21.6 is_abstract: false cert_requests: [] diff --git a/packages/valory/connections/abci/gogoproto/gogo_pb2.py b/packages/valory/connections/abci/gogoproto/gogo_pb2.py index c0483f5fa9..e02509ae4a 100644 --- a/packages/valory/connections/abci/gogoproto/gogo_pb2.py +++ b/packages/valory/connections/abci/gogoproto/gogo_pb2.py @@ -3,9 +3,9 @@ # source: gogoproto/gogo.proto """Generated protocol buffer code.""" from google.protobuf import descriptor as _descriptor -from google.protobuf import message as _message -from google.protobuf import reflection as _reflection +from google.protobuf import descriptor_pool as _descriptor_pool from google.protobuf import symbol_database as _symbol_database +from google.protobuf.internal import builder as _builder # @@protoc_insertion_point(imports) @@ -16,1742 +16,16 @@ from google.protobuf import descriptor_pb2 as google_dot_protobuf_dot_descriptor__pb2 -DESCRIPTOR = _descriptor.FileDescriptor( - name="gogoproto/gogo.proto", - package="gogoproto", - syntax="proto2", - serialized_options=b'\n\023com.google.protobufB\nGoGoProtosZ"github.com/gogo/protobuf/gogoproto', - create_key=_descriptor._internal_create_key, - serialized_pb=b'\n\x14gogoproto/gogo.proto\x12\tgogoproto\x1a google/protobuf/descriptor.proto:;\n\x13goproto_enum_prefix\x12\x1c.google.protobuf.EnumOptions\x18\xb1\xe4\x03 \x01(\x08:=\n\x15goproto_enum_stringer\x12\x1c.google.protobuf.EnumOptions\x18\xc5\xe4\x03 \x01(\x08:5\n\renum_stringer\x12\x1c.google.protobuf.EnumOptions\x18\xc6\xe4\x03 \x01(\x08:7\n\x0f\x65num_customname\x12\x1c.google.protobuf.EnumOptions\x18\xc7\xe4\x03 \x01(\t:0\n\x08\x65numdecl\x12\x1c.google.protobuf.EnumOptions\x18\xc8\xe4\x03 \x01(\x08:A\n\x14\x65numvalue_customname\x12!.google.protobuf.EnumValueOptions\x18\xd1\x83\x04 \x01(\t:;\n\x13goproto_getters_all\x12\x1c.google.protobuf.FileOptions\x18\x99\xec\x03 \x01(\x08:?\n\x17goproto_enum_prefix_all\x12\x1c.google.protobuf.FileOptions\x18\x9a\xec\x03 \x01(\x08:<\n\x14goproto_stringer_all\x12\x1c.google.protobuf.FileOptions\x18\x9b\xec\x03 \x01(\x08:9\n\x11verbose_equal_all\x12\x1c.google.protobuf.FileOptions\x18\x9c\xec\x03 \x01(\x08:0\n\x08\x66\x61\x63\x65_all\x12\x1c.google.protobuf.FileOptions\x18\x9d\xec\x03 \x01(\x08:4\n\x0cgostring_all\x12\x1c.google.protobuf.FileOptions\x18\x9e\xec\x03 \x01(\x08:4\n\x0cpopulate_all\x12\x1c.google.protobuf.FileOptions\x18\x9f\xec\x03 \x01(\x08:4\n\x0cstringer_all\x12\x1c.google.protobuf.FileOptions\x18\xa0\xec\x03 \x01(\x08:3\n\x0bonlyone_all\x12\x1c.google.protobuf.FileOptions\x18\xa1\xec\x03 \x01(\x08:1\n\tequal_all\x12\x1c.google.protobuf.FileOptions\x18\xa5\xec\x03 \x01(\x08:7\n\x0f\x64\x65scription_all\x12\x1c.google.protobuf.FileOptions\x18\xa6\xec\x03 \x01(\x08:3\n\x0btestgen_all\x12\x1c.google.protobuf.FileOptions\x18\xa7\xec\x03 \x01(\x08:4\n\x0c\x62\x65nchgen_all\x12\x1c.google.protobuf.FileOptions\x18\xa8\xec\x03 \x01(\x08:5\n\rmarshaler_all\x12\x1c.google.protobuf.FileOptions\x18\xa9\xec\x03 \x01(\x08:7\n\x0funmarshaler_all\x12\x1c.google.protobuf.FileOptions\x18\xaa\xec\x03 \x01(\x08:<\n\x14stable_marshaler_all\x12\x1c.google.protobuf.FileOptions\x18\xab\xec\x03 \x01(\x08:1\n\tsizer_all\x12\x1c.google.protobuf.FileOptions\x18\xac\xec\x03 \x01(\x08:A\n\x19goproto_enum_stringer_all\x12\x1c.google.protobuf.FileOptions\x18\xad\xec\x03 \x01(\x08:9\n\x11\x65num_stringer_all\x12\x1c.google.protobuf.FileOptions\x18\xae\xec\x03 \x01(\x08:<\n\x14unsafe_marshaler_all\x12\x1c.google.protobuf.FileOptions\x18\xaf\xec\x03 \x01(\x08:>\n\x16unsafe_unmarshaler_all\x12\x1c.google.protobuf.FileOptions\x18\xb0\xec\x03 \x01(\x08:B\n\x1agoproto_extensions_map_all\x12\x1c.google.protobuf.FileOptions\x18\xb1\xec\x03 \x01(\x08:@\n\x18goproto_unrecognized_all\x12\x1c.google.protobuf.FileOptions\x18\xb2\xec\x03 \x01(\x08:8\n\x10gogoproto_import\x12\x1c.google.protobuf.FileOptions\x18\xb3\xec\x03 \x01(\x08:6\n\x0eprotosizer_all\x12\x1c.google.protobuf.FileOptions\x18\xb4\xec\x03 \x01(\x08:3\n\x0b\x63ompare_all\x12\x1c.google.protobuf.FileOptions\x18\xb5\xec\x03 \x01(\x08:4\n\x0ctypedecl_all\x12\x1c.google.protobuf.FileOptions\x18\xb6\xec\x03 \x01(\x08:4\n\x0c\x65numdecl_all\x12\x1c.google.protobuf.FileOptions\x18\xb7\xec\x03 \x01(\x08:<\n\x14goproto_registration\x12\x1c.google.protobuf.FileOptions\x18\xb8\xec\x03 \x01(\x08:7\n\x0fmessagename_all\x12\x1c.google.protobuf.FileOptions\x18\xb9\xec\x03 \x01(\x08:=\n\x15goproto_sizecache_all\x12\x1c.google.protobuf.FileOptions\x18\xba\xec\x03 \x01(\x08:;\n\x13goproto_unkeyed_all\x12\x1c.google.protobuf.FileOptions\x18\xbb\xec\x03 \x01(\x08::\n\x0fgoproto_getters\x12\x1f.google.protobuf.MessageOptions\x18\x81\xf4\x03 \x01(\x08:;\n\x10goproto_stringer\x12\x1f.google.protobuf.MessageOptions\x18\x83\xf4\x03 \x01(\x08:8\n\rverbose_equal\x12\x1f.google.protobuf.MessageOptions\x18\x84\xf4\x03 \x01(\x08:/\n\x04\x66\x61\x63\x65\x12\x1f.google.protobuf.MessageOptions\x18\x85\xf4\x03 \x01(\x08:3\n\x08gostring\x12\x1f.google.protobuf.MessageOptions\x18\x86\xf4\x03 \x01(\x08:3\n\x08populate\x12\x1f.google.protobuf.MessageOptions\x18\x87\xf4\x03 \x01(\x08:3\n\x08stringer\x12\x1f.google.protobuf.MessageOptions\x18\xc0\x8b\x04 \x01(\x08:2\n\x07onlyone\x12\x1f.google.protobuf.MessageOptions\x18\x89\xf4\x03 \x01(\x08:0\n\x05\x65qual\x12\x1f.google.protobuf.MessageOptions\x18\x8d\xf4\x03 \x01(\x08:6\n\x0b\x64\x65scription\x12\x1f.google.protobuf.MessageOptions\x18\x8e\xf4\x03 \x01(\x08:2\n\x07testgen\x12\x1f.google.protobuf.MessageOptions\x18\x8f\xf4\x03 \x01(\x08:3\n\x08\x62\x65nchgen\x12\x1f.google.protobuf.MessageOptions\x18\x90\xf4\x03 \x01(\x08:4\n\tmarshaler\x12\x1f.google.protobuf.MessageOptions\x18\x91\xf4\x03 \x01(\x08:6\n\x0bunmarshaler\x12\x1f.google.protobuf.MessageOptions\x18\x92\xf4\x03 \x01(\x08:;\n\x10stable_marshaler\x12\x1f.google.protobuf.MessageOptions\x18\x93\xf4\x03 \x01(\x08:0\n\x05sizer\x12\x1f.google.protobuf.MessageOptions\x18\x94\xf4\x03 \x01(\x08:;\n\x10unsafe_marshaler\x12\x1f.google.protobuf.MessageOptions\x18\x97\xf4\x03 \x01(\x08:=\n\x12unsafe_unmarshaler\x12\x1f.google.protobuf.MessageOptions\x18\x98\xf4\x03 \x01(\x08:A\n\x16goproto_extensions_map\x12\x1f.google.protobuf.MessageOptions\x18\x99\xf4\x03 \x01(\x08:?\n\x14goproto_unrecognized\x12\x1f.google.protobuf.MessageOptions\x18\x9a\xf4\x03 \x01(\x08:5\n\nprotosizer\x12\x1f.google.protobuf.MessageOptions\x18\x9c\xf4\x03 \x01(\x08:2\n\x07\x63ompare\x12\x1f.google.protobuf.MessageOptions\x18\x9d\xf4\x03 \x01(\x08:3\n\x08typedecl\x12\x1f.google.protobuf.MessageOptions\x18\x9e\xf4\x03 \x01(\x08:6\n\x0bmessagename\x12\x1f.google.protobuf.MessageOptions\x18\xa1\xf4\x03 \x01(\x08:<\n\x11goproto_sizecache\x12\x1f.google.protobuf.MessageOptions\x18\xa2\xf4\x03 \x01(\x08::\n\x0fgoproto_unkeyed\x12\x1f.google.protobuf.MessageOptions\x18\xa3\xf4\x03 \x01(\x08:1\n\x08nullable\x12\x1d.google.protobuf.FieldOptions\x18\xe9\xfb\x03 \x01(\x08:.\n\x05\x65mbed\x12\x1d.google.protobuf.FieldOptions\x18\xea\xfb\x03 \x01(\x08:3\n\ncustomtype\x12\x1d.google.protobuf.FieldOptions\x18\xeb\xfb\x03 \x01(\t:3\n\ncustomname\x12\x1d.google.protobuf.FieldOptions\x18\xec\xfb\x03 \x01(\t:0\n\x07jsontag\x12\x1d.google.protobuf.FieldOptions\x18\xed\xfb\x03 \x01(\t:1\n\x08moretags\x12\x1d.google.protobuf.FieldOptions\x18\xee\xfb\x03 \x01(\t:1\n\x08\x63\x61sttype\x12\x1d.google.protobuf.FieldOptions\x18\xef\xfb\x03 \x01(\t:0\n\x07\x63\x61stkey\x12\x1d.google.protobuf.FieldOptions\x18\xf0\xfb\x03 \x01(\t:2\n\tcastvalue\x12\x1d.google.protobuf.FieldOptions\x18\xf1\xfb\x03 \x01(\t:0\n\x07stdtime\x12\x1d.google.protobuf.FieldOptions\x18\xf2\xfb\x03 \x01(\x08:4\n\x0bstdduration\x12\x1d.google.protobuf.FieldOptions\x18\xf3\xfb\x03 \x01(\x08:3\n\nwktpointer\x12\x1d.google.protobuf.FieldOptions\x18\xf4\xfb\x03 \x01(\x08\x42\x45\n\x13\x63om.google.protobufB\nGoGoProtosZ"github.com/gogo/protobuf/gogoproto', - dependencies=[ - google_dot_protobuf_dot_descriptor__pb2.DESCRIPTOR, - ], +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile( + b'\n\x14gogoproto/gogo.proto\x12\tgogoproto\x1a google/protobuf/descriptor.proto:;\n\x13goproto_enum_prefix\x12\x1c.google.protobuf.EnumOptions\x18\xb1\xe4\x03 \x01(\x08:=\n\x15goproto_enum_stringer\x12\x1c.google.protobuf.EnumOptions\x18\xc5\xe4\x03 \x01(\x08:5\n\renum_stringer\x12\x1c.google.protobuf.EnumOptions\x18\xc6\xe4\x03 \x01(\x08:7\n\x0f\x65num_customname\x12\x1c.google.protobuf.EnumOptions\x18\xc7\xe4\x03 \x01(\t:0\n\x08\x65numdecl\x12\x1c.google.protobuf.EnumOptions\x18\xc8\xe4\x03 \x01(\x08:A\n\x14\x65numvalue_customname\x12!.google.protobuf.EnumValueOptions\x18\xd1\x83\x04 \x01(\t:;\n\x13goproto_getters_all\x12\x1c.google.protobuf.FileOptions\x18\x99\xec\x03 \x01(\x08:?\n\x17goproto_enum_prefix_all\x12\x1c.google.protobuf.FileOptions\x18\x9a\xec\x03 \x01(\x08:<\n\x14goproto_stringer_all\x12\x1c.google.protobuf.FileOptions\x18\x9b\xec\x03 \x01(\x08:9\n\x11verbose_equal_all\x12\x1c.google.protobuf.FileOptions\x18\x9c\xec\x03 \x01(\x08:0\n\x08\x66\x61\x63\x65_all\x12\x1c.google.protobuf.FileOptions\x18\x9d\xec\x03 \x01(\x08:4\n\x0cgostring_all\x12\x1c.google.protobuf.FileOptions\x18\x9e\xec\x03 \x01(\x08:4\n\x0cpopulate_all\x12\x1c.google.protobuf.FileOptions\x18\x9f\xec\x03 \x01(\x08:4\n\x0cstringer_all\x12\x1c.google.protobuf.FileOptions\x18\xa0\xec\x03 \x01(\x08:3\n\x0bonlyone_all\x12\x1c.google.protobuf.FileOptions\x18\xa1\xec\x03 \x01(\x08:1\n\tequal_all\x12\x1c.google.protobuf.FileOptions\x18\xa5\xec\x03 \x01(\x08:7\n\x0f\x64\x65scription_all\x12\x1c.google.protobuf.FileOptions\x18\xa6\xec\x03 \x01(\x08:3\n\x0btestgen_all\x12\x1c.google.protobuf.FileOptions\x18\xa7\xec\x03 \x01(\x08:4\n\x0c\x62\x65nchgen_all\x12\x1c.google.protobuf.FileOptions\x18\xa8\xec\x03 \x01(\x08:5\n\rmarshaler_all\x12\x1c.google.protobuf.FileOptions\x18\xa9\xec\x03 \x01(\x08:7\n\x0funmarshaler_all\x12\x1c.google.protobuf.FileOptions\x18\xaa\xec\x03 \x01(\x08:<\n\x14stable_marshaler_all\x12\x1c.google.protobuf.FileOptions\x18\xab\xec\x03 \x01(\x08:1\n\tsizer_all\x12\x1c.google.protobuf.FileOptions\x18\xac\xec\x03 \x01(\x08:A\n\x19goproto_enum_stringer_all\x12\x1c.google.protobuf.FileOptions\x18\xad\xec\x03 \x01(\x08:9\n\x11\x65num_stringer_all\x12\x1c.google.protobuf.FileOptions\x18\xae\xec\x03 \x01(\x08:<\n\x14unsafe_marshaler_all\x12\x1c.google.protobuf.FileOptions\x18\xaf\xec\x03 \x01(\x08:>\n\x16unsafe_unmarshaler_all\x12\x1c.google.protobuf.FileOptions\x18\xb0\xec\x03 \x01(\x08:B\n\x1agoproto_extensions_map_all\x12\x1c.google.protobuf.FileOptions\x18\xb1\xec\x03 \x01(\x08:@\n\x18goproto_unrecognized_all\x12\x1c.google.protobuf.FileOptions\x18\xb2\xec\x03 \x01(\x08:8\n\x10gogoproto_import\x12\x1c.google.protobuf.FileOptions\x18\xb3\xec\x03 \x01(\x08:6\n\x0eprotosizer_all\x12\x1c.google.protobuf.FileOptions\x18\xb4\xec\x03 \x01(\x08:3\n\x0b\x63ompare_all\x12\x1c.google.protobuf.FileOptions\x18\xb5\xec\x03 \x01(\x08:4\n\x0ctypedecl_all\x12\x1c.google.protobuf.FileOptions\x18\xb6\xec\x03 \x01(\x08:4\n\x0c\x65numdecl_all\x12\x1c.google.protobuf.FileOptions\x18\xb7\xec\x03 \x01(\x08:<\n\x14goproto_registration\x12\x1c.google.protobuf.FileOptions\x18\xb8\xec\x03 \x01(\x08:7\n\x0fmessagename_all\x12\x1c.google.protobuf.FileOptions\x18\xb9\xec\x03 \x01(\x08:=\n\x15goproto_sizecache_all\x12\x1c.google.protobuf.FileOptions\x18\xba\xec\x03 \x01(\x08:;\n\x13goproto_unkeyed_all\x12\x1c.google.protobuf.FileOptions\x18\xbb\xec\x03 \x01(\x08::\n\x0fgoproto_getters\x12\x1f.google.protobuf.MessageOptions\x18\x81\xf4\x03 \x01(\x08:;\n\x10goproto_stringer\x12\x1f.google.protobuf.MessageOptions\x18\x83\xf4\x03 \x01(\x08:8\n\rverbose_equal\x12\x1f.google.protobuf.MessageOptions\x18\x84\xf4\x03 \x01(\x08:/\n\x04\x66\x61\x63\x65\x12\x1f.google.protobuf.MessageOptions\x18\x85\xf4\x03 \x01(\x08:3\n\x08gostring\x12\x1f.google.protobuf.MessageOptions\x18\x86\xf4\x03 \x01(\x08:3\n\x08populate\x12\x1f.google.protobuf.MessageOptions\x18\x87\xf4\x03 \x01(\x08:3\n\x08stringer\x12\x1f.google.protobuf.MessageOptions\x18\xc0\x8b\x04 \x01(\x08:2\n\x07onlyone\x12\x1f.google.protobuf.MessageOptions\x18\x89\xf4\x03 \x01(\x08:0\n\x05\x65qual\x12\x1f.google.protobuf.MessageOptions\x18\x8d\xf4\x03 \x01(\x08:6\n\x0b\x64\x65scription\x12\x1f.google.protobuf.MessageOptions\x18\x8e\xf4\x03 \x01(\x08:2\n\x07testgen\x12\x1f.google.protobuf.MessageOptions\x18\x8f\xf4\x03 \x01(\x08:3\n\x08\x62\x65nchgen\x12\x1f.google.protobuf.MessageOptions\x18\x90\xf4\x03 \x01(\x08:4\n\tmarshaler\x12\x1f.google.protobuf.MessageOptions\x18\x91\xf4\x03 \x01(\x08:6\n\x0bunmarshaler\x12\x1f.google.protobuf.MessageOptions\x18\x92\xf4\x03 \x01(\x08:;\n\x10stable_marshaler\x12\x1f.google.protobuf.MessageOptions\x18\x93\xf4\x03 \x01(\x08:0\n\x05sizer\x12\x1f.google.protobuf.MessageOptions\x18\x94\xf4\x03 \x01(\x08:;\n\x10unsafe_marshaler\x12\x1f.google.protobuf.MessageOptions\x18\x97\xf4\x03 \x01(\x08:=\n\x12unsafe_unmarshaler\x12\x1f.google.protobuf.MessageOptions\x18\x98\xf4\x03 \x01(\x08:A\n\x16goproto_extensions_map\x12\x1f.google.protobuf.MessageOptions\x18\x99\xf4\x03 \x01(\x08:?\n\x14goproto_unrecognized\x12\x1f.google.protobuf.MessageOptions\x18\x9a\xf4\x03 \x01(\x08:5\n\nprotosizer\x12\x1f.google.protobuf.MessageOptions\x18\x9c\xf4\x03 \x01(\x08:2\n\x07\x63ompare\x12\x1f.google.protobuf.MessageOptions\x18\x9d\xf4\x03 \x01(\x08:3\n\x08typedecl\x12\x1f.google.protobuf.MessageOptions\x18\x9e\xf4\x03 \x01(\x08:6\n\x0bmessagename\x12\x1f.google.protobuf.MessageOptions\x18\xa1\xf4\x03 \x01(\x08:<\n\x11goproto_sizecache\x12\x1f.google.protobuf.MessageOptions\x18\xa2\xf4\x03 \x01(\x08::\n\x0fgoproto_unkeyed\x12\x1f.google.protobuf.MessageOptions\x18\xa3\xf4\x03 \x01(\x08:1\n\x08nullable\x12\x1d.google.protobuf.FieldOptions\x18\xe9\xfb\x03 \x01(\x08:.\n\x05\x65mbed\x12\x1d.google.protobuf.FieldOptions\x18\xea\xfb\x03 \x01(\x08:3\n\ncustomtype\x12\x1d.google.protobuf.FieldOptions\x18\xeb\xfb\x03 \x01(\t:3\n\ncustomname\x12\x1d.google.protobuf.FieldOptions\x18\xec\xfb\x03 \x01(\t:0\n\x07jsontag\x12\x1d.google.protobuf.FieldOptions\x18\xed\xfb\x03 \x01(\t:1\n\x08moretags\x12\x1d.google.protobuf.FieldOptions\x18\xee\xfb\x03 \x01(\t:1\n\x08\x63\x61sttype\x12\x1d.google.protobuf.FieldOptions\x18\xef\xfb\x03 \x01(\t:0\n\x07\x63\x61stkey\x12\x1d.google.protobuf.FieldOptions\x18\xf0\xfb\x03 \x01(\t:2\n\tcastvalue\x12\x1d.google.protobuf.FieldOptions\x18\xf1\xfb\x03 \x01(\t:0\n\x07stdtime\x12\x1d.google.protobuf.FieldOptions\x18\xf2\xfb\x03 \x01(\x08:4\n\x0bstdduration\x12\x1d.google.protobuf.FieldOptions\x18\xf3\xfb\x03 \x01(\x08:3\n\nwktpointer\x12\x1d.google.protobuf.FieldOptions\x18\xf4\xfb\x03 \x01(\x08\x42\x45\n\x13\x63om.google.protobufB\nGoGoProtosZ"github.com/gogo/protobuf/gogoproto' ) - -GOPROTO_ENUM_PREFIX_FIELD_NUMBER = 62001 -goproto_enum_prefix = _descriptor.FieldDescriptor( - name="goproto_enum_prefix", - full_name="gogoproto.goproto_enum_prefix", - index=0, - number=62001, - type=8, - cpp_type=7, - label=1, - has_default_value=False, - default_value=False, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=True, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, -) -GOPROTO_ENUM_STRINGER_FIELD_NUMBER = 62021 -goproto_enum_stringer = _descriptor.FieldDescriptor( - name="goproto_enum_stringer", - full_name="gogoproto.goproto_enum_stringer", - index=1, - number=62021, - type=8, - cpp_type=7, - label=1, - has_default_value=False, - default_value=False, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=True, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, -) -ENUM_STRINGER_FIELD_NUMBER = 62022 -enum_stringer = _descriptor.FieldDescriptor( - name="enum_stringer", - full_name="gogoproto.enum_stringer", - index=2, - number=62022, - type=8, - cpp_type=7, - label=1, - has_default_value=False, - default_value=False, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=True, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, -) -ENUM_CUSTOMNAME_FIELD_NUMBER = 62023 -enum_customname = _descriptor.FieldDescriptor( - name="enum_customname", - full_name="gogoproto.enum_customname", - index=3, - number=62023, - type=9, - cpp_type=9, - label=1, - has_default_value=False, - default_value=b"".decode("utf-8"), - message_type=None, - enum_type=None, - containing_type=None, - is_extension=True, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, -) -ENUMDECL_FIELD_NUMBER = 62024 -enumdecl = _descriptor.FieldDescriptor( - name="enumdecl", - full_name="gogoproto.enumdecl", - index=4, - number=62024, - type=8, - cpp_type=7, - label=1, - has_default_value=False, - default_value=False, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=True, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, -) -ENUMVALUE_CUSTOMNAME_FIELD_NUMBER = 66001 -enumvalue_customname = _descriptor.FieldDescriptor( - name="enumvalue_customname", - full_name="gogoproto.enumvalue_customname", - index=5, - number=66001, - type=9, - cpp_type=9, - label=1, - has_default_value=False, - default_value=b"".decode("utf-8"), - message_type=None, - enum_type=None, - containing_type=None, - is_extension=True, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, -) -GOPROTO_GETTERS_ALL_FIELD_NUMBER = 63001 -goproto_getters_all = _descriptor.FieldDescriptor( - name="goproto_getters_all", - full_name="gogoproto.goproto_getters_all", - index=6, - number=63001, - type=8, - cpp_type=7, - label=1, - has_default_value=False, - default_value=False, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=True, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, -) -GOPROTO_ENUM_PREFIX_ALL_FIELD_NUMBER = 63002 -goproto_enum_prefix_all = _descriptor.FieldDescriptor( - name="goproto_enum_prefix_all", - full_name="gogoproto.goproto_enum_prefix_all", - index=7, - number=63002, - type=8, - cpp_type=7, - label=1, - has_default_value=False, - default_value=False, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=True, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, -) -GOPROTO_STRINGER_ALL_FIELD_NUMBER = 63003 -goproto_stringer_all = _descriptor.FieldDescriptor( - name="goproto_stringer_all", - full_name="gogoproto.goproto_stringer_all", - index=8, - number=63003, - type=8, - cpp_type=7, - label=1, - has_default_value=False, - default_value=False, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=True, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, -) -VERBOSE_EQUAL_ALL_FIELD_NUMBER = 63004 -verbose_equal_all = _descriptor.FieldDescriptor( - name="verbose_equal_all", - full_name="gogoproto.verbose_equal_all", - index=9, - number=63004, - type=8, - cpp_type=7, - label=1, - has_default_value=False, - default_value=False, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=True, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, -) -FACE_ALL_FIELD_NUMBER = 63005 -face_all = _descriptor.FieldDescriptor( - name="face_all", - full_name="gogoproto.face_all", - index=10, - number=63005, - type=8, - cpp_type=7, - label=1, - has_default_value=False, - default_value=False, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=True, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, -) -GOSTRING_ALL_FIELD_NUMBER = 63006 -gostring_all = _descriptor.FieldDescriptor( - name="gostring_all", - full_name="gogoproto.gostring_all", - index=11, - number=63006, - type=8, - cpp_type=7, - label=1, - has_default_value=False, - default_value=False, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=True, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, -) -POPULATE_ALL_FIELD_NUMBER = 63007 -populate_all = _descriptor.FieldDescriptor( - name="populate_all", - full_name="gogoproto.populate_all", - index=12, - number=63007, - type=8, - cpp_type=7, - label=1, - has_default_value=False, - default_value=False, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=True, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, -) -STRINGER_ALL_FIELD_NUMBER = 63008 -stringer_all = _descriptor.FieldDescriptor( - name="stringer_all", - full_name="gogoproto.stringer_all", - index=13, - number=63008, - type=8, - cpp_type=7, - label=1, - has_default_value=False, - default_value=False, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=True, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, -) -ONLYONE_ALL_FIELD_NUMBER = 63009 -onlyone_all = _descriptor.FieldDescriptor( - name="onlyone_all", - full_name="gogoproto.onlyone_all", - index=14, - number=63009, - type=8, - cpp_type=7, - label=1, - has_default_value=False, - default_value=False, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=True, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, -) -EQUAL_ALL_FIELD_NUMBER = 63013 -equal_all = _descriptor.FieldDescriptor( - name="equal_all", - full_name="gogoproto.equal_all", - index=15, - number=63013, - type=8, - cpp_type=7, - label=1, - has_default_value=False, - default_value=False, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=True, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, -) -DESCRIPTION_ALL_FIELD_NUMBER = 63014 -description_all = _descriptor.FieldDescriptor( - name="description_all", - full_name="gogoproto.description_all", - index=16, - number=63014, - type=8, - cpp_type=7, - label=1, - has_default_value=False, - default_value=False, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=True, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, -) -TESTGEN_ALL_FIELD_NUMBER = 63015 -testgen_all = _descriptor.FieldDescriptor( - name="testgen_all", - full_name="gogoproto.testgen_all", - index=17, - number=63015, - type=8, - cpp_type=7, - label=1, - has_default_value=False, - default_value=False, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=True, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, -) -BENCHGEN_ALL_FIELD_NUMBER = 63016 -benchgen_all = _descriptor.FieldDescriptor( - name="benchgen_all", - full_name="gogoproto.benchgen_all", - index=18, - number=63016, - type=8, - cpp_type=7, - label=1, - has_default_value=False, - default_value=False, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=True, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, -) -MARSHALER_ALL_FIELD_NUMBER = 63017 -marshaler_all = _descriptor.FieldDescriptor( - name="marshaler_all", - full_name="gogoproto.marshaler_all", - index=19, - number=63017, - type=8, - cpp_type=7, - label=1, - has_default_value=False, - default_value=False, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=True, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, -) -UNMARSHALER_ALL_FIELD_NUMBER = 63018 -unmarshaler_all = _descriptor.FieldDescriptor( - name="unmarshaler_all", - full_name="gogoproto.unmarshaler_all", - index=20, - number=63018, - type=8, - cpp_type=7, - label=1, - has_default_value=False, - default_value=False, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=True, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, -) -STABLE_MARSHALER_ALL_FIELD_NUMBER = 63019 -stable_marshaler_all = _descriptor.FieldDescriptor( - name="stable_marshaler_all", - full_name="gogoproto.stable_marshaler_all", - index=21, - number=63019, - type=8, - cpp_type=7, - label=1, - has_default_value=False, - default_value=False, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=True, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, -) -SIZER_ALL_FIELD_NUMBER = 63020 -sizer_all = _descriptor.FieldDescriptor( - name="sizer_all", - full_name="gogoproto.sizer_all", - index=22, - number=63020, - type=8, - cpp_type=7, - label=1, - has_default_value=False, - default_value=False, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=True, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, -) -GOPROTO_ENUM_STRINGER_ALL_FIELD_NUMBER = 63021 -goproto_enum_stringer_all = _descriptor.FieldDescriptor( - name="goproto_enum_stringer_all", - full_name="gogoproto.goproto_enum_stringer_all", - index=23, - number=63021, - type=8, - cpp_type=7, - label=1, - has_default_value=False, - default_value=False, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=True, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, -) -ENUM_STRINGER_ALL_FIELD_NUMBER = 63022 -enum_stringer_all = _descriptor.FieldDescriptor( - name="enum_stringer_all", - full_name="gogoproto.enum_stringer_all", - index=24, - number=63022, - type=8, - cpp_type=7, - label=1, - has_default_value=False, - default_value=False, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=True, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, -) -UNSAFE_MARSHALER_ALL_FIELD_NUMBER = 63023 -unsafe_marshaler_all = _descriptor.FieldDescriptor( - name="unsafe_marshaler_all", - full_name="gogoproto.unsafe_marshaler_all", - index=25, - number=63023, - type=8, - cpp_type=7, - label=1, - has_default_value=False, - default_value=False, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=True, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, -) -UNSAFE_UNMARSHALER_ALL_FIELD_NUMBER = 63024 -unsafe_unmarshaler_all = _descriptor.FieldDescriptor( - name="unsafe_unmarshaler_all", - full_name="gogoproto.unsafe_unmarshaler_all", - index=26, - number=63024, - type=8, - cpp_type=7, - label=1, - has_default_value=False, - default_value=False, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=True, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, -) -GOPROTO_EXTENSIONS_MAP_ALL_FIELD_NUMBER = 63025 -goproto_extensions_map_all = _descriptor.FieldDescriptor( - name="goproto_extensions_map_all", - full_name="gogoproto.goproto_extensions_map_all", - index=27, - number=63025, - type=8, - cpp_type=7, - label=1, - has_default_value=False, - default_value=False, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=True, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, -) -GOPROTO_UNRECOGNIZED_ALL_FIELD_NUMBER = 63026 -goproto_unrecognized_all = _descriptor.FieldDescriptor( - name="goproto_unrecognized_all", - full_name="gogoproto.goproto_unrecognized_all", - index=28, - number=63026, - type=8, - cpp_type=7, - label=1, - has_default_value=False, - default_value=False, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=True, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, -) -GOGOPROTO_IMPORT_FIELD_NUMBER = 63027 -gogoproto_import = _descriptor.FieldDescriptor( - name="gogoproto_import", - full_name="gogoproto.gogoproto_import", - index=29, - number=63027, - type=8, - cpp_type=7, - label=1, - has_default_value=False, - default_value=False, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=True, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, -) -PROTOSIZER_ALL_FIELD_NUMBER = 63028 -protosizer_all = _descriptor.FieldDescriptor( - name="protosizer_all", - full_name="gogoproto.protosizer_all", - index=30, - number=63028, - type=8, - cpp_type=7, - label=1, - has_default_value=False, - default_value=False, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=True, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, -) -COMPARE_ALL_FIELD_NUMBER = 63029 -compare_all = _descriptor.FieldDescriptor( - name="compare_all", - full_name="gogoproto.compare_all", - index=31, - number=63029, - type=8, - cpp_type=7, - label=1, - has_default_value=False, - default_value=False, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=True, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, -) -TYPEDECL_ALL_FIELD_NUMBER = 63030 -typedecl_all = _descriptor.FieldDescriptor( - name="typedecl_all", - full_name="gogoproto.typedecl_all", - index=32, - number=63030, - type=8, - cpp_type=7, - label=1, - has_default_value=False, - default_value=False, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=True, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, -) -ENUMDECL_ALL_FIELD_NUMBER = 63031 -enumdecl_all = _descriptor.FieldDescriptor( - name="enumdecl_all", - full_name="gogoproto.enumdecl_all", - index=33, - number=63031, - type=8, - cpp_type=7, - label=1, - has_default_value=False, - default_value=False, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=True, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, -) -GOPROTO_REGISTRATION_FIELD_NUMBER = 63032 -goproto_registration = _descriptor.FieldDescriptor( - name="goproto_registration", - full_name="gogoproto.goproto_registration", - index=34, - number=63032, - type=8, - cpp_type=7, - label=1, - has_default_value=False, - default_value=False, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=True, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, -) -MESSAGENAME_ALL_FIELD_NUMBER = 63033 -messagename_all = _descriptor.FieldDescriptor( - name="messagename_all", - full_name="gogoproto.messagename_all", - index=35, - number=63033, - type=8, - cpp_type=7, - label=1, - has_default_value=False, - default_value=False, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=True, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, -) -GOPROTO_SIZECACHE_ALL_FIELD_NUMBER = 63034 -goproto_sizecache_all = _descriptor.FieldDescriptor( - name="goproto_sizecache_all", - full_name="gogoproto.goproto_sizecache_all", - index=36, - number=63034, - type=8, - cpp_type=7, - label=1, - has_default_value=False, - default_value=False, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=True, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, -) -GOPROTO_UNKEYED_ALL_FIELD_NUMBER = 63035 -goproto_unkeyed_all = _descriptor.FieldDescriptor( - name="goproto_unkeyed_all", - full_name="gogoproto.goproto_unkeyed_all", - index=37, - number=63035, - type=8, - cpp_type=7, - label=1, - has_default_value=False, - default_value=False, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=True, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, -) -GOPROTO_GETTERS_FIELD_NUMBER = 64001 -goproto_getters = _descriptor.FieldDescriptor( - name="goproto_getters", - full_name="gogoproto.goproto_getters", - index=38, - number=64001, - type=8, - cpp_type=7, - label=1, - has_default_value=False, - default_value=False, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=True, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, -) -GOPROTO_STRINGER_FIELD_NUMBER = 64003 -goproto_stringer = _descriptor.FieldDescriptor( - name="goproto_stringer", - full_name="gogoproto.goproto_stringer", - index=39, - number=64003, - type=8, - cpp_type=7, - label=1, - has_default_value=False, - default_value=False, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=True, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, -) -VERBOSE_EQUAL_FIELD_NUMBER = 64004 -verbose_equal = _descriptor.FieldDescriptor( - name="verbose_equal", - full_name="gogoproto.verbose_equal", - index=40, - number=64004, - type=8, - cpp_type=7, - label=1, - has_default_value=False, - default_value=False, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=True, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, -) -FACE_FIELD_NUMBER = 64005 -face = _descriptor.FieldDescriptor( - name="face", - full_name="gogoproto.face", - index=41, - number=64005, - type=8, - cpp_type=7, - label=1, - has_default_value=False, - default_value=False, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=True, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, -) -GOSTRING_FIELD_NUMBER = 64006 -gostring = _descriptor.FieldDescriptor( - name="gostring", - full_name="gogoproto.gostring", - index=42, - number=64006, - type=8, - cpp_type=7, - label=1, - has_default_value=False, - default_value=False, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=True, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, -) -POPULATE_FIELD_NUMBER = 64007 -populate = _descriptor.FieldDescriptor( - name="populate", - full_name="gogoproto.populate", - index=43, - number=64007, - type=8, - cpp_type=7, - label=1, - has_default_value=False, - default_value=False, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=True, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, -) -STRINGER_FIELD_NUMBER = 67008 -stringer = _descriptor.FieldDescriptor( - name="stringer", - full_name="gogoproto.stringer", - index=44, - number=67008, - type=8, - cpp_type=7, - label=1, - has_default_value=False, - default_value=False, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=True, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, -) -ONLYONE_FIELD_NUMBER = 64009 -onlyone = _descriptor.FieldDescriptor( - name="onlyone", - full_name="gogoproto.onlyone", - index=45, - number=64009, - type=8, - cpp_type=7, - label=1, - has_default_value=False, - default_value=False, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=True, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, -) -EQUAL_FIELD_NUMBER = 64013 -equal = _descriptor.FieldDescriptor( - name="equal", - full_name="gogoproto.equal", - index=46, - number=64013, - type=8, - cpp_type=7, - label=1, - has_default_value=False, - default_value=False, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=True, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, -) -DESCRIPTION_FIELD_NUMBER = 64014 -description = _descriptor.FieldDescriptor( - name="description", - full_name="gogoproto.description", - index=47, - number=64014, - type=8, - cpp_type=7, - label=1, - has_default_value=False, - default_value=False, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=True, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, -) -TESTGEN_FIELD_NUMBER = 64015 -testgen = _descriptor.FieldDescriptor( - name="testgen", - full_name="gogoproto.testgen", - index=48, - number=64015, - type=8, - cpp_type=7, - label=1, - has_default_value=False, - default_value=False, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=True, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, -) -BENCHGEN_FIELD_NUMBER = 64016 -benchgen = _descriptor.FieldDescriptor( - name="benchgen", - full_name="gogoproto.benchgen", - index=49, - number=64016, - type=8, - cpp_type=7, - label=1, - has_default_value=False, - default_value=False, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=True, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, -) -MARSHALER_FIELD_NUMBER = 64017 -marshaler = _descriptor.FieldDescriptor( - name="marshaler", - full_name="gogoproto.marshaler", - index=50, - number=64017, - type=8, - cpp_type=7, - label=1, - has_default_value=False, - default_value=False, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=True, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, -) -UNMARSHALER_FIELD_NUMBER = 64018 -unmarshaler = _descriptor.FieldDescriptor( - name="unmarshaler", - full_name="gogoproto.unmarshaler", - index=51, - number=64018, - type=8, - cpp_type=7, - label=1, - has_default_value=False, - default_value=False, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=True, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, -) -STABLE_MARSHALER_FIELD_NUMBER = 64019 -stable_marshaler = _descriptor.FieldDescriptor( - name="stable_marshaler", - full_name="gogoproto.stable_marshaler", - index=52, - number=64019, - type=8, - cpp_type=7, - label=1, - has_default_value=False, - default_value=False, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=True, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, -) -SIZER_FIELD_NUMBER = 64020 -sizer = _descriptor.FieldDescriptor( - name="sizer", - full_name="gogoproto.sizer", - index=53, - number=64020, - type=8, - cpp_type=7, - label=1, - has_default_value=False, - default_value=False, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=True, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, -) -UNSAFE_MARSHALER_FIELD_NUMBER = 64023 -unsafe_marshaler = _descriptor.FieldDescriptor( - name="unsafe_marshaler", - full_name="gogoproto.unsafe_marshaler", - index=54, - number=64023, - type=8, - cpp_type=7, - label=1, - has_default_value=False, - default_value=False, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=True, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, -) -UNSAFE_UNMARSHALER_FIELD_NUMBER = 64024 -unsafe_unmarshaler = _descriptor.FieldDescriptor( - name="unsafe_unmarshaler", - full_name="gogoproto.unsafe_unmarshaler", - index=55, - number=64024, - type=8, - cpp_type=7, - label=1, - has_default_value=False, - default_value=False, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=True, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, -) -GOPROTO_EXTENSIONS_MAP_FIELD_NUMBER = 64025 -goproto_extensions_map = _descriptor.FieldDescriptor( - name="goproto_extensions_map", - full_name="gogoproto.goproto_extensions_map", - index=56, - number=64025, - type=8, - cpp_type=7, - label=1, - has_default_value=False, - default_value=False, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=True, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, -) -GOPROTO_UNRECOGNIZED_FIELD_NUMBER = 64026 -goproto_unrecognized = _descriptor.FieldDescriptor( - name="goproto_unrecognized", - full_name="gogoproto.goproto_unrecognized", - index=57, - number=64026, - type=8, - cpp_type=7, - label=1, - has_default_value=False, - default_value=False, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=True, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, -) -PROTOSIZER_FIELD_NUMBER = 64028 -protosizer = _descriptor.FieldDescriptor( - name="protosizer", - full_name="gogoproto.protosizer", - index=58, - number=64028, - type=8, - cpp_type=7, - label=1, - has_default_value=False, - default_value=False, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=True, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, -) -COMPARE_FIELD_NUMBER = 64029 -compare = _descriptor.FieldDescriptor( - name="compare", - full_name="gogoproto.compare", - index=59, - number=64029, - type=8, - cpp_type=7, - label=1, - has_default_value=False, - default_value=False, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=True, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, -) -TYPEDECL_FIELD_NUMBER = 64030 -typedecl = _descriptor.FieldDescriptor( - name="typedecl", - full_name="gogoproto.typedecl", - index=60, - number=64030, - type=8, - cpp_type=7, - label=1, - has_default_value=False, - default_value=False, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=True, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, -) -MESSAGENAME_FIELD_NUMBER = 64033 -messagename = _descriptor.FieldDescriptor( - name="messagename", - full_name="gogoproto.messagename", - index=61, - number=64033, - type=8, - cpp_type=7, - label=1, - has_default_value=False, - default_value=False, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=True, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, -) -GOPROTO_SIZECACHE_FIELD_NUMBER = 64034 -goproto_sizecache = _descriptor.FieldDescriptor( - name="goproto_sizecache", - full_name="gogoproto.goproto_sizecache", - index=62, - number=64034, - type=8, - cpp_type=7, - label=1, - has_default_value=False, - default_value=False, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=True, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, -) -GOPROTO_UNKEYED_FIELD_NUMBER = 64035 -goproto_unkeyed = _descriptor.FieldDescriptor( - name="goproto_unkeyed", - full_name="gogoproto.goproto_unkeyed", - index=63, - number=64035, - type=8, - cpp_type=7, - label=1, - has_default_value=False, - default_value=False, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=True, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, -) -NULLABLE_FIELD_NUMBER = 65001 -nullable = _descriptor.FieldDescriptor( - name="nullable", - full_name="gogoproto.nullable", - index=64, - number=65001, - type=8, - cpp_type=7, - label=1, - has_default_value=False, - default_value=False, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=True, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, -) -EMBED_FIELD_NUMBER = 65002 -embed = _descriptor.FieldDescriptor( - name="embed", - full_name="gogoproto.embed", - index=65, - number=65002, - type=8, - cpp_type=7, - label=1, - has_default_value=False, - default_value=False, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=True, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, -) -CUSTOMTYPE_FIELD_NUMBER = 65003 -customtype = _descriptor.FieldDescriptor( - name="customtype", - full_name="gogoproto.customtype", - index=66, - number=65003, - type=9, - cpp_type=9, - label=1, - has_default_value=False, - default_value=b"".decode("utf-8"), - message_type=None, - enum_type=None, - containing_type=None, - is_extension=True, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, -) -CUSTOMNAME_FIELD_NUMBER = 65004 -customname = _descriptor.FieldDescriptor( - name="customname", - full_name="gogoproto.customname", - index=67, - number=65004, - type=9, - cpp_type=9, - label=1, - has_default_value=False, - default_value=b"".decode("utf-8"), - message_type=None, - enum_type=None, - containing_type=None, - is_extension=True, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, -) -JSONTAG_FIELD_NUMBER = 65005 -jsontag = _descriptor.FieldDescriptor( - name="jsontag", - full_name="gogoproto.jsontag", - index=68, - number=65005, - type=9, - cpp_type=9, - label=1, - has_default_value=False, - default_value=b"".decode("utf-8"), - message_type=None, - enum_type=None, - containing_type=None, - is_extension=True, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, -) -MORETAGS_FIELD_NUMBER = 65006 -moretags = _descriptor.FieldDescriptor( - name="moretags", - full_name="gogoproto.moretags", - index=69, - number=65006, - type=9, - cpp_type=9, - label=1, - has_default_value=False, - default_value=b"".decode("utf-8"), - message_type=None, - enum_type=None, - containing_type=None, - is_extension=True, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, -) -CASTTYPE_FIELD_NUMBER = 65007 -casttype = _descriptor.FieldDescriptor( - name="casttype", - full_name="gogoproto.casttype", - index=70, - number=65007, - type=9, - cpp_type=9, - label=1, - has_default_value=False, - default_value=b"".decode("utf-8"), - message_type=None, - enum_type=None, - containing_type=None, - is_extension=True, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, -) -CASTKEY_FIELD_NUMBER = 65008 -castkey = _descriptor.FieldDescriptor( - name="castkey", - full_name="gogoproto.castkey", - index=71, - number=65008, - type=9, - cpp_type=9, - label=1, - has_default_value=False, - default_value=b"".decode("utf-8"), - message_type=None, - enum_type=None, - containing_type=None, - is_extension=True, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, -) -CASTVALUE_FIELD_NUMBER = 65009 -castvalue = _descriptor.FieldDescriptor( - name="castvalue", - full_name="gogoproto.castvalue", - index=72, - number=65009, - type=9, - cpp_type=9, - label=1, - has_default_value=False, - default_value=b"".decode("utf-8"), - message_type=None, - enum_type=None, - containing_type=None, - is_extension=True, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, -) -STDTIME_FIELD_NUMBER = 65010 -stdtime = _descriptor.FieldDescriptor( - name="stdtime", - full_name="gogoproto.stdtime", - index=73, - number=65010, - type=8, - cpp_type=7, - label=1, - has_default_value=False, - default_value=False, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=True, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, -) -STDDURATION_FIELD_NUMBER = 65011 -stdduration = _descriptor.FieldDescriptor( - name="stdduration", - full_name="gogoproto.stdduration", - index=74, - number=65011, - type=8, - cpp_type=7, - label=1, - has_default_value=False, - default_value=False, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=True, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, -) -WKTPOINTER_FIELD_NUMBER = 65012 -wktpointer = _descriptor.FieldDescriptor( - name="wktpointer", - full_name="gogoproto.wktpointer", - index=75, - number=65012, - type=8, - cpp_type=7, - label=1, - has_default_value=False, - default_value=False, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=True, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, -) - -DESCRIPTOR.extensions_by_name["goproto_enum_prefix"] = goproto_enum_prefix -DESCRIPTOR.extensions_by_name["goproto_enum_stringer"] = goproto_enum_stringer -DESCRIPTOR.extensions_by_name["enum_stringer"] = enum_stringer -DESCRIPTOR.extensions_by_name["enum_customname"] = enum_customname -DESCRIPTOR.extensions_by_name["enumdecl"] = enumdecl -DESCRIPTOR.extensions_by_name["enumvalue_customname"] = enumvalue_customname -DESCRIPTOR.extensions_by_name["goproto_getters_all"] = goproto_getters_all -DESCRIPTOR.extensions_by_name["goproto_enum_prefix_all"] = goproto_enum_prefix_all -DESCRIPTOR.extensions_by_name["goproto_stringer_all"] = goproto_stringer_all -DESCRIPTOR.extensions_by_name["verbose_equal_all"] = verbose_equal_all -DESCRIPTOR.extensions_by_name["face_all"] = face_all -DESCRIPTOR.extensions_by_name["gostring_all"] = gostring_all -DESCRIPTOR.extensions_by_name["populate_all"] = populate_all -DESCRIPTOR.extensions_by_name["stringer_all"] = stringer_all -DESCRIPTOR.extensions_by_name["onlyone_all"] = onlyone_all -DESCRIPTOR.extensions_by_name["equal_all"] = equal_all -DESCRIPTOR.extensions_by_name["description_all"] = description_all -DESCRIPTOR.extensions_by_name["testgen_all"] = testgen_all -DESCRIPTOR.extensions_by_name["benchgen_all"] = benchgen_all -DESCRIPTOR.extensions_by_name["marshaler_all"] = marshaler_all -DESCRIPTOR.extensions_by_name["unmarshaler_all"] = unmarshaler_all -DESCRIPTOR.extensions_by_name["stable_marshaler_all"] = stable_marshaler_all -DESCRIPTOR.extensions_by_name["sizer_all"] = sizer_all -DESCRIPTOR.extensions_by_name["goproto_enum_stringer_all"] = goproto_enum_stringer_all -DESCRIPTOR.extensions_by_name["enum_stringer_all"] = enum_stringer_all -DESCRIPTOR.extensions_by_name["unsafe_marshaler_all"] = unsafe_marshaler_all -DESCRIPTOR.extensions_by_name["unsafe_unmarshaler_all"] = unsafe_unmarshaler_all -DESCRIPTOR.extensions_by_name["goproto_extensions_map_all"] = goproto_extensions_map_all -DESCRIPTOR.extensions_by_name["goproto_unrecognized_all"] = goproto_unrecognized_all -DESCRIPTOR.extensions_by_name["gogoproto_import"] = gogoproto_import -DESCRIPTOR.extensions_by_name["protosizer_all"] = protosizer_all -DESCRIPTOR.extensions_by_name["compare_all"] = compare_all -DESCRIPTOR.extensions_by_name["typedecl_all"] = typedecl_all -DESCRIPTOR.extensions_by_name["enumdecl_all"] = enumdecl_all -DESCRIPTOR.extensions_by_name["goproto_registration"] = goproto_registration -DESCRIPTOR.extensions_by_name["messagename_all"] = messagename_all -DESCRIPTOR.extensions_by_name["goproto_sizecache_all"] = goproto_sizecache_all -DESCRIPTOR.extensions_by_name["goproto_unkeyed_all"] = goproto_unkeyed_all -DESCRIPTOR.extensions_by_name["goproto_getters"] = goproto_getters -DESCRIPTOR.extensions_by_name["goproto_stringer"] = goproto_stringer -DESCRIPTOR.extensions_by_name["verbose_equal"] = verbose_equal -DESCRIPTOR.extensions_by_name["face"] = face -DESCRIPTOR.extensions_by_name["gostring"] = gostring -DESCRIPTOR.extensions_by_name["populate"] = populate -DESCRIPTOR.extensions_by_name["stringer"] = stringer -DESCRIPTOR.extensions_by_name["onlyone"] = onlyone -DESCRIPTOR.extensions_by_name["equal"] = equal -DESCRIPTOR.extensions_by_name["description"] = description -DESCRIPTOR.extensions_by_name["testgen"] = testgen -DESCRIPTOR.extensions_by_name["benchgen"] = benchgen -DESCRIPTOR.extensions_by_name["marshaler"] = marshaler -DESCRIPTOR.extensions_by_name["unmarshaler"] = unmarshaler -DESCRIPTOR.extensions_by_name["stable_marshaler"] = stable_marshaler -DESCRIPTOR.extensions_by_name["sizer"] = sizer -DESCRIPTOR.extensions_by_name["unsafe_marshaler"] = unsafe_marshaler -DESCRIPTOR.extensions_by_name["unsafe_unmarshaler"] = unsafe_unmarshaler -DESCRIPTOR.extensions_by_name["goproto_extensions_map"] = goproto_extensions_map -DESCRIPTOR.extensions_by_name["goproto_unrecognized"] = goproto_unrecognized -DESCRIPTOR.extensions_by_name["protosizer"] = protosizer -DESCRIPTOR.extensions_by_name["compare"] = compare -DESCRIPTOR.extensions_by_name["typedecl"] = typedecl -DESCRIPTOR.extensions_by_name["messagename"] = messagename -DESCRIPTOR.extensions_by_name["goproto_sizecache"] = goproto_sizecache -DESCRIPTOR.extensions_by_name["goproto_unkeyed"] = goproto_unkeyed -DESCRIPTOR.extensions_by_name["nullable"] = nullable -DESCRIPTOR.extensions_by_name["embed"] = embed -DESCRIPTOR.extensions_by_name["customtype"] = customtype -DESCRIPTOR.extensions_by_name["customname"] = customname -DESCRIPTOR.extensions_by_name["jsontag"] = jsontag -DESCRIPTOR.extensions_by_name["moretags"] = moretags -DESCRIPTOR.extensions_by_name["casttype"] = casttype -DESCRIPTOR.extensions_by_name["castkey"] = castkey -DESCRIPTOR.extensions_by_name["castvalue"] = castvalue -DESCRIPTOR.extensions_by_name["stdtime"] = stdtime -DESCRIPTOR.extensions_by_name["stdduration"] = stdduration -DESCRIPTOR.extensions_by_name["wktpointer"] = wktpointer -_sym_db.RegisterFileDescriptor(DESCRIPTOR) - -google_dot_protobuf_dot_descriptor__pb2.EnumOptions.RegisterExtension( - goproto_enum_prefix -) -google_dot_protobuf_dot_descriptor__pb2.EnumOptions.RegisterExtension( - goproto_enum_stringer -) -google_dot_protobuf_dot_descriptor__pb2.EnumOptions.RegisterExtension(enum_stringer) -google_dot_protobuf_dot_descriptor__pb2.EnumOptions.RegisterExtension(enum_customname) -google_dot_protobuf_dot_descriptor__pb2.EnumOptions.RegisterExtension(enumdecl) -google_dot_protobuf_dot_descriptor__pb2.EnumValueOptions.RegisterExtension( - enumvalue_customname -) -google_dot_protobuf_dot_descriptor__pb2.FileOptions.RegisterExtension( - goproto_getters_all -) -google_dot_protobuf_dot_descriptor__pb2.FileOptions.RegisterExtension( - goproto_enum_prefix_all -) -google_dot_protobuf_dot_descriptor__pb2.FileOptions.RegisterExtension( - goproto_stringer_all -) -google_dot_protobuf_dot_descriptor__pb2.FileOptions.RegisterExtension(verbose_equal_all) -google_dot_protobuf_dot_descriptor__pb2.FileOptions.RegisterExtension(face_all) -google_dot_protobuf_dot_descriptor__pb2.FileOptions.RegisterExtension(gostring_all) -google_dot_protobuf_dot_descriptor__pb2.FileOptions.RegisterExtension(populate_all) -google_dot_protobuf_dot_descriptor__pb2.FileOptions.RegisterExtension(stringer_all) -google_dot_protobuf_dot_descriptor__pb2.FileOptions.RegisterExtension(onlyone_all) -google_dot_protobuf_dot_descriptor__pb2.FileOptions.RegisterExtension(equal_all) -google_dot_protobuf_dot_descriptor__pb2.FileOptions.RegisterExtension(description_all) -google_dot_protobuf_dot_descriptor__pb2.FileOptions.RegisterExtension(testgen_all) -google_dot_protobuf_dot_descriptor__pb2.FileOptions.RegisterExtension(benchgen_all) -google_dot_protobuf_dot_descriptor__pb2.FileOptions.RegisterExtension(marshaler_all) -google_dot_protobuf_dot_descriptor__pb2.FileOptions.RegisterExtension(unmarshaler_all) -google_dot_protobuf_dot_descriptor__pb2.FileOptions.RegisterExtension( - stable_marshaler_all -) -google_dot_protobuf_dot_descriptor__pb2.FileOptions.RegisterExtension(sizer_all) -google_dot_protobuf_dot_descriptor__pb2.FileOptions.RegisterExtension( - goproto_enum_stringer_all -) -google_dot_protobuf_dot_descriptor__pb2.FileOptions.RegisterExtension(enum_stringer_all) -google_dot_protobuf_dot_descriptor__pb2.FileOptions.RegisterExtension( - unsafe_marshaler_all -) -google_dot_protobuf_dot_descriptor__pb2.FileOptions.RegisterExtension( - unsafe_unmarshaler_all -) -google_dot_protobuf_dot_descriptor__pb2.FileOptions.RegisterExtension( - goproto_extensions_map_all -) -google_dot_protobuf_dot_descriptor__pb2.FileOptions.RegisterExtension( - goproto_unrecognized_all -) -google_dot_protobuf_dot_descriptor__pb2.FileOptions.RegisterExtension(gogoproto_import) -google_dot_protobuf_dot_descriptor__pb2.FileOptions.RegisterExtension(protosizer_all) -google_dot_protobuf_dot_descriptor__pb2.FileOptions.RegisterExtension(compare_all) -google_dot_protobuf_dot_descriptor__pb2.FileOptions.RegisterExtension(typedecl_all) -google_dot_protobuf_dot_descriptor__pb2.FileOptions.RegisterExtension(enumdecl_all) -google_dot_protobuf_dot_descriptor__pb2.FileOptions.RegisterExtension( - goproto_registration -) -google_dot_protobuf_dot_descriptor__pb2.FileOptions.RegisterExtension(messagename_all) -google_dot_protobuf_dot_descriptor__pb2.FileOptions.RegisterExtension( - goproto_sizecache_all -) -google_dot_protobuf_dot_descriptor__pb2.FileOptions.RegisterExtension( - goproto_unkeyed_all -) -google_dot_protobuf_dot_descriptor__pb2.MessageOptions.RegisterExtension( - goproto_getters -) -google_dot_protobuf_dot_descriptor__pb2.MessageOptions.RegisterExtension( - goproto_stringer -) -google_dot_protobuf_dot_descriptor__pb2.MessageOptions.RegisterExtension(verbose_equal) -google_dot_protobuf_dot_descriptor__pb2.MessageOptions.RegisterExtension(face) -google_dot_protobuf_dot_descriptor__pb2.MessageOptions.RegisterExtension(gostring) -google_dot_protobuf_dot_descriptor__pb2.MessageOptions.RegisterExtension(populate) -google_dot_protobuf_dot_descriptor__pb2.MessageOptions.RegisterExtension(stringer) -google_dot_protobuf_dot_descriptor__pb2.MessageOptions.RegisterExtension(onlyone) -google_dot_protobuf_dot_descriptor__pb2.MessageOptions.RegisterExtension(equal) -google_dot_protobuf_dot_descriptor__pb2.MessageOptions.RegisterExtension(description) -google_dot_protobuf_dot_descriptor__pb2.MessageOptions.RegisterExtension(testgen) -google_dot_protobuf_dot_descriptor__pb2.MessageOptions.RegisterExtension(benchgen) -google_dot_protobuf_dot_descriptor__pb2.MessageOptions.RegisterExtension(marshaler) -google_dot_protobuf_dot_descriptor__pb2.MessageOptions.RegisterExtension(unmarshaler) -google_dot_protobuf_dot_descriptor__pb2.MessageOptions.RegisterExtension( - stable_marshaler -) -google_dot_protobuf_dot_descriptor__pb2.MessageOptions.RegisterExtension(sizer) -google_dot_protobuf_dot_descriptor__pb2.MessageOptions.RegisterExtension( - unsafe_marshaler -) -google_dot_protobuf_dot_descriptor__pb2.MessageOptions.RegisterExtension( - unsafe_unmarshaler -) -google_dot_protobuf_dot_descriptor__pb2.MessageOptions.RegisterExtension( - goproto_extensions_map -) -google_dot_protobuf_dot_descriptor__pb2.MessageOptions.RegisterExtension( - goproto_unrecognized -) -google_dot_protobuf_dot_descriptor__pb2.MessageOptions.RegisterExtension(protosizer) -google_dot_protobuf_dot_descriptor__pb2.MessageOptions.RegisterExtension(compare) -google_dot_protobuf_dot_descriptor__pb2.MessageOptions.RegisterExtension(typedecl) -google_dot_protobuf_dot_descriptor__pb2.MessageOptions.RegisterExtension(messagename) -google_dot_protobuf_dot_descriptor__pb2.MessageOptions.RegisterExtension( - goproto_sizecache -) -google_dot_protobuf_dot_descriptor__pb2.MessageOptions.RegisterExtension( - goproto_unkeyed -) -google_dot_protobuf_dot_descriptor__pb2.FieldOptions.RegisterExtension(nullable) -google_dot_protobuf_dot_descriptor__pb2.FieldOptions.RegisterExtension(embed) -google_dot_protobuf_dot_descriptor__pb2.FieldOptions.RegisterExtension(customtype) -google_dot_protobuf_dot_descriptor__pb2.FieldOptions.RegisterExtension(customname) -google_dot_protobuf_dot_descriptor__pb2.FieldOptions.RegisterExtension(jsontag) -google_dot_protobuf_dot_descriptor__pb2.FieldOptions.RegisterExtension(moretags) -google_dot_protobuf_dot_descriptor__pb2.FieldOptions.RegisterExtension(casttype) -google_dot_protobuf_dot_descriptor__pb2.FieldOptions.RegisterExtension(castkey) -google_dot_protobuf_dot_descriptor__pb2.FieldOptions.RegisterExtension(castvalue) -google_dot_protobuf_dot_descriptor__pb2.FieldOptions.RegisterExtension(stdtime) -google_dot_protobuf_dot_descriptor__pb2.FieldOptions.RegisterExtension(stdduration) -google_dot_protobuf_dot_descriptor__pb2.FieldOptions.RegisterExtension(wktpointer) - -DESCRIPTOR._options = None +_globals = globals() +_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) +_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, "gogoproto.gogo_pb2", _globals) +if _descriptor._USE_C_DESCRIPTORS == False: + DESCRIPTOR._options = None + DESCRIPTOR._serialized_options = ( + b'\n\023com.google.protobufB\nGoGoProtosZ"github.com/gogo/protobuf/gogoproto' + ) # @@protoc_insertion_point(module_scope) diff --git a/packages/valory/connections/abci/tendermint/abci/types_pb2.py b/packages/valory/connections/abci/tendermint/abci/types_pb2.py index c9df52328f..6f94ff4baf 100644 --- a/packages/valory/connections/abci/tendermint/abci/types_pb2.py +++ b/packages/valory/connections/abci/tendermint/abci/types_pb2.py @@ -3,10 +3,9 @@ # source: tendermint/abci/types.proto """Generated protocol buffer code.""" from google.protobuf import descriptor as _descriptor -from google.protobuf import message as _message -from google.protobuf import reflection as _reflection +from google.protobuf import descriptor_pool as _descriptor_pool from google.protobuf import symbol_database as _symbol_database -from google.protobuf.internal import enum_type_wrapper +from google.protobuf.internal import builder as _builder # @@protoc_insertion_point(imports) @@ -33,4926 +32,180 @@ ) -DESCRIPTOR = _descriptor.FileDescriptor( - name="tendermint/abci/types.proto", - package="tendermint.abci", - syntax="proto3", - serialized_options=b"Z+github.com/tendermint/tendermint/abci/types", - create_key=_descriptor._internal_create_key, - serialized_pb=b'\n\x1btendermint/abci/types.proto\x12\x0ftendermint.abci\x1a\x1dtendermint/crypto/proof.proto\x1a\x1ctendermint/types/types.proto\x1a\x1ctendermint/crypto/keys.proto\x1a\x1dtendermint/types/params.proto\x1a\x1fgoogle/protobuf/timestamp.proto\x1a\x14gogoproto/gogo.proto"\xea\x06\n\x07Request\x12,\n\x04\x65\x63ho\x18\x01 \x01(\x0b\x32\x1c.tendermint.abci.RequestEchoH\x00\x12.\n\x05\x66lush\x18\x02 \x01(\x0b\x32\x1d.tendermint.abci.RequestFlushH\x00\x12,\n\x04info\x18\x03 \x01(\x0b\x32\x1c.tendermint.abci.RequestInfoH\x00\x12\x37\n\nset_option\x18\x04 \x01(\x0b\x32!.tendermint.abci.RequestSetOptionH\x00\x12\x37\n\ninit_chain\x18\x05 \x01(\x0b\x32!.tendermint.abci.RequestInitChainH\x00\x12.\n\x05query\x18\x06 \x01(\x0b\x32\x1d.tendermint.abci.RequestQueryH\x00\x12\x39\n\x0b\x62\x65gin_block\x18\x07 \x01(\x0b\x32".tendermint.abci.RequestBeginBlockH\x00\x12\x33\n\x08\x63heck_tx\x18\x08 \x01(\x0b\x32\x1f.tendermint.abci.RequestCheckTxH\x00\x12\x37\n\ndeliver_tx\x18\t \x01(\x0b\x32!.tendermint.abci.RequestDeliverTxH\x00\x12\x35\n\tend_block\x18\n \x01(\x0b\x32 .tendermint.abci.RequestEndBlockH\x00\x12\x30\n\x06\x63ommit\x18\x0b \x01(\x0b\x32\x1e.tendermint.abci.RequestCommitH\x00\x12?\n\x0elist_snapshots\x18\x0c \x01(\x0b\x32%.tendermint.abci.RequestListSnapshotsH\x00\x12?\n\x0eoffer_snapshot\x18\r \x01(\x0b\x32%.tendermint.abci.RequestOfferSnapshotH\x00\x12H\n\x13load_snapshot_chunk\x18\x0e \x01(\x0b\x32).tendermint.abci.RequestLoadSnapshotChunkH\x00\x12J\n\x14\x61pply_snapshot_chunk\x18\x0f \x01(\x0b\x32*.tendermint.abci.RequestApplySnapshotChunkH\x00\x42\x07\n\x05value"\x1e\n\x0bRequestEcho\x12\x0f\n\x07message\x18\x01 \x01(\t"\x0e\n\x0cRequestFlush"J\n\x0bRequestInfo\x12\x0f\n\x07version\x18\x01 \x01(\t\x12\x15\n\rblock_version\x18\x02 \x01(\x04\x12\x13\n\x0bp2p_version\x18\x03 \x01(\x04".\n\x10RequestSetOption\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t"\x81\x02\n\x10RequestInitChain\x12\x32\n\x04time\x18\x01 \x01(\x0b\x32\x1a.google.protobuf.TimestampB\x08\xc8\xde\x1f\x00\x90\xdf\x1f\x01\x12\x10\n\x08\x63hain_id\x18\x02 \x01(\t\x12:\n\x10\x63onsensus_params\x18\x03 \x01(\x0b\x32 .tendermint.abci.ConsensusParams\x12:\n\nvalidators\x18\x04 \x03(\x0b\x32 .tendermint.abci.ValidatorUpdateB\x04\xc8\xde\x1f\x00\x12\x17\n\x0f\x61pp_state_bytes\x18\x05 \x01(\x0c\x12\x16\n\x0einitial_height\x18\x06 \x01(\x03"I\n\x0cRequestQuery\x12\x0c\n\x04\x64\x61ta\x18\x01 \x01(\x0c\x12\x0c\n\x04path\x18\x02 \x01(\t\x12\x0e\n\x06height\x18\x03 \x01(\x03\x12\r\n\x05prove\x18\x04 \x01(\x08"\xd1\x01\n\x11RequestBeginBlock\x12\x0c\n\x04hash\x18\x01 \x01(\x0c\x12.\n\x06header\x18\x02 \x01(\x0b\x32\x18.tendermint.types.HeaderB\x04\xc8\xde\x1f\x00\x12?\n\x10last_commit_info\x18\x03 \x01(\x0b\x32\x1f.tendermint.abci.LastCommitInfoB\x04\xc8\xde\x1f\x00\x12=\n\x14\x62yzantine_validators\x18\x04 \x03(\x0b\x32\x19.tendermint.abci.EvidenceB\x04\xc8\xde\x1f\x00"H\n\x0eRequestCheckTx\x12\n\n\x02tx\x18\x01 \x01(\x0c\x12*\n\x04type\x18\x02 \x01(\x0e\x32\x1c.tendermint.abci.CheckTxType"\x1e\n\x10RequestDeliverTx\x12\n\n\x02tx\x18\x01 \x01(\x0c"!\n\x0fRequestEndBlock\x12\x0e\n\x06height\x18\x01 \x01(\x03"\x0f\n\rRequestCommit"\x16\n\x14RequestListSnapshots"U\n\x14RequestOfferSnapshot\x12+\n\x08snapshot\x18\x01 \x01(\x0b\x32\x19.tendermint.abci.Snapshot\x12\x10\n\x08\x61pp_hash\x18\x02 \x01(\x0c"I\n\x18RequestLoadSnapshotChunk\x12\x0e\n\x06height\x18\x01 \x01(\x04\x12\x0e\n\x06\x66ormat\x18\x02 \x01(\r\x12\r\n\x05\x63hunk\x18\x03 \x01(\r"I\n\x19RequestApplySnapshotChunk\x12\r\n\x05index\x18\x01 \x01(\r\x12\r\n\x05\x63hunk\x18\x02 \x01(\x0c\x12\x0e\n\x06sender\x18\x03 \x01(\t"\xb3\x07\n\x08Response\x12\x37\n\texception\x18\x01 \x01(\x0b\x32".tendermint.abci.ResponseExceptionH\x00\x12-\n\x04\x65\x63ho\x18\x02 \x01(\x0b\x32\x1d.tendermint.abci.ResponseEchoH\x00\x12/\n\x05\x66lush\x18\x03 \x01(\x0b\x32\x1e.tendermint.abci.ResponseFlushH\x00\x12-\n\x04info\x18\x04 \x01(\x0b\x32\x1d.tendermint.abci.ResponseInfoH\x00\x12\x38\n\nset_option\x18\x05 \x01(\x0b\x32".tendermint.abci.ResponseSetOptionH\x00\x12\x38\n\ninit_chain\x18\x06 \x01(\x0b\x32".tendermint.abci.ResponseInitChainH\x00\x12/\n\x05query\x18\x07 \x01(\x0b\x32\x1e.tendermint.abci.ResponseQueryH\x00\x12:\n\x0b\x62\x65gin_block\x18\x08 \x01(\x0b\x32#.tendermint.abci.ResponseBeginBlockH\x00\x12\x34\n\x08\x63heck_tx\x18\t \x01(\x0b\x32 .tendermint.abci.ResponseCheckTxH\x00\x12\x38\n\ndeliver_tx\x18\n \x01(\x0b\x32".tendermint.abci.ResponseDeliverTxH\x00\x12\x36\n\tend_block\x18\x0b \x01(\x0b\x32!.tendermint.abci.ResponseEndBlockH\x00\x12\x31\n\x06\x63ommit\x18\x0c \x01(\x0b\x32\x1f.tendermint.abci.ResponseCommitH\x00\x12@\n\x0elist_snapshots\x18\r \x01(\x0b\x32&.tendermint.abci.ResponseListSnapshotsH\x00\x12@\n\x0eoffer_snapshot\x18\x0e \x01(\x0b\x32&.tendermint.abci.ResponseOfferSnapshotH\x00\x12I\n\x13load_snapshot_chunk\x18\x0f \x01(\x0b\x32*.tendermint.abci.ResponseLoadSnapshotChunkH\x00\x12K\n\x14\x61pply_snapshot_chunk\x18\x10 \x01(\x0b\x32+.tendermint.abci.ResponseApplySnapshotChunkH\x00\x42\x07\n\x05value""\n\x11ResponseException\x12\r\n\x05\x65rror\x18\x01 \x01(\t"\x1f\n\x0cResponseEcho\x12\x0f\n\x07message\x18\x01 \x01(\t"\x0f\n\rResponseFlush"z\n\x0cResponseInfo\x12\x0c\n\x04\x64\x61ta\x18\x01 \x01(\t\x12\x0f\n\x07version\x18\x02 \x01(\t\x12\x13\n\x0b\x61pp_version\x18\x03 \x01(\x04\x12\x19\n\x11last_block_height\x18\x04 \x01(\x03\x12\x1b\n\x13last_block_app_hash\x18\x05 \x01(\x0c"<\n\x11ResponseSetOption\x12\x0c\n\x04\x63ode\x18\x01 \x01(\r\x12\x0b\n\x03log\x18\x03 \x01(\t\x12\x0c\n\x04info\x18\x04 \x01(\t"\x9d\x01\n\x11ResponseInitChain\x12:\n\x10\x63onsensus_params\x18\x01 \x01(\x0b\x32 .tendermint.abci.ConsensusParams\x12:\n\nvalidators\x18\x02 \x03(\x0b\x32 .tendermint.abci.ValidatorUpdateB\x04\xc8\xde\x1f\x00\x12\x10\n\x08\x61pp_hash\x18\x03 \x01(\x0c"\xb6\x01\n\rResponseQuery\x12\x0c\n\x04\x63ode\x18\x01 \x01(\r\x12\x0b\n\x03log\x18\x03 \x01(\t\x12\x0c\n\x04info\x18\x04 \x01(\t\x12\r\n\x05index\x18\x05 \x01(\x03\x12\x0b\n\x03key\x18\x06 \x01(\x0c\x12\r\n\x05value\x18\x07 \x01(\x0c\x12.\n\tproof_ops\x18\x08 \x01(\x0b\x32\x1b.tendermint.crypto.ProofOps\x12\x0e\n\x06height\x18\t \x01(\x03\x12\x11\n\tcodespace\x18\n \x01(\t"V\n\x12ResponseBeginBlock\x12@\n\x06\x65vents\x18\x01 \x03(\x0b\x32\x16.tendermint.abci.EventB\x18\xc8\xde\x1f\x00\xea\xde\x1f\x10\x65vents,omitempty"\xd9\x01\n\x0fResponseCheckTx\x12\x0c\n\x04\x63ode\x18\x01 \x01(\r\x12\x0c\n\x04\x64\x61ta\x18\x02 \x01(\x0c\x12\x0b\n\x03log\x18\x03 \x01(\t\x12\x0c\n\x04info\x18\x04 \x01(\t\x12\x1e\n\ngas_wanted\x18\x05 \x01(\x03R\ngas_wanted\x12\x1a\n\x08gas_used\x18\x06 \x01(\x03R\x08gas_used\x12@\n\x06\x65vents\x18\x07 \x03(\x0b\x32\x16.tendermint.abci.EventB\x18\xc8\xde\x1f\x00\xea\xde\x1f\x10\x65vents,omitempty\x12\x11\n\tcodespace\x18\x08 \x01(\t"\xdb\x01\n\x11ResponseDeliverTx\x12\x0c\n\x04\x63ode\x18\x01 \x01(\r\x12\x0c\n\x04\x64\x61ta\x18\x02 \x01(\x0c\x12\x0b\n\x03log\x18\x03 \x01(\t\x12\x0c\n\x04info\x18\x04 \x01(\t\x12\x1e\n\ngas_wanted\x18\x05 \x01(\x03R\ngas_wanted\x12\x1a\n\x08gas_used\x18\x06 \x01(\x03R\x08gas_used\x12@\n\x06\x65vents\x18\x07 \x03(\x0b\x32\x16.tendermint.abci.EventB\x18\xc8\xde\x1f\x00\xea\xde\x1f\x10\x65vents,omitempty\x12\x11\n\tcodespace\x18\x08 \x01(\t"\xda\x01\n\x10ResponseEndBlock\x12\x41\n\x11validator_updates\x18\x01 \x03(\x0b\x32 .tendermint.abci.ValidatorUpdateB\x04\xc8\xde\x1f\x00\x12\x41\n\x17\x63onsensus_param_updates\x18\x02 \x01(\x0b\x32 .tendermint.abci.ConsensusParams\x12@\n\x06\x65vents\x18\x03 \x03(\x0b\x32\x16.tendermint.abci.EventB\x18\xc8\xde\x1f\x00\xea\xde\x1f\x10\x65vents,omitempty"5\n\x0eResponseCommit\x12\x0c\n\x04\x64\x61ta\x18\x02 \x01(\x0c\x12\x15\n\rretain_height\x18\x03 \x01(\x03"E\n\x15ResponseListSnapshots\x12,\n\tsnapshots\x18\x01 \x03(\x0b\x32\x19.tendermint.abci.Snapshot"\xb6\x01\n\x15ResponseOfferSnapshot\x12=\n\x06result\x18\x01 \x01(\x0e\x32-.tendermint.abci.ResponseOfferSnapshot.Result"^\n\x06Result\x12\x0b\n\x07UNKNOWN\x10\x00\x12\n\n\x06\x41\x43\x43\x45PT\x10\x01\x12\t\n\x05\x41\x42ORT\x10\x02\x12\n\n\x06REJECT\x10\x03\x12\x11\n\rREJECT_FORMAT\x10\x04\x12\x11\n\rREJECT_SENDER\x10\x05"*\n\x19ResponseLoadSnapshotChunk\x12\r\n\x05\x63hunk\x18\x01 \x01(\x0c"\xf2\x01\n\x1aResponseApplySnapshotChunk\x12\x42\n\x06result\x18\x01 \x01(\x0e\x32\x32.tendermint.abci.ResponseApplySnapshotChunk.Result\x12\x16\n\x0erefetch_chunks\x18\x02 \x03(\r\x12\x16\n\x0ereject_senders\x18\x03 \x03(\t"`\n\x06Result\x12\x0b\n\x07UNKNOWN\x10\x00\x12\n\n\x06\x41\x43\x43\x45PT\x10\x01\x12\t\n\x05\x41\x42ORT\x10\x02\x12\t\n\x05RETRY\x10\x03\x12\x12\n\x0eRETRY_SNAPSHOT\x10\x04\x12\x13\n\x0fREJECT_SNAPSHOT\x10\x05"\xda\x01\n\x0f\x43onsensusParams\x12+\n\x05\x62lock\x18\x01 \x01(\x0b\x32\x1c.tendermint.abci.BlockParams\x12\x32\n\x08\x65vidence\x18\x02 \x01(\x0b\x32 .tendermint.types.EvidenceParams\x12\x34\n\tvalidator\x18\x03 \x01(\x0b\x32!.tendermint.types.ValidatorParams\x12\x30\n\x07version\x18\x04 \x01(\x0b\x32\x1f.tendermint.types.VersionParams"1\n\x0b\x42lockParams\x12\x11\n\tmax_bytes\x18\x01 \x01(\x03\x12\x0f\n\x07max_gas\x18\x02 \x01(\x03"O\n\x0eLastCommitInfo\x12\r\n\x05round\x18\x01 \x01(\x05\x12.\n\x05votes\x18\x02 \x03(\x0b\x32\x19.tendermint.abci.VoteInfoB\x04\xc8\xde\x1f\x00"h\n\x05\x45vent\x12\x0c\n\x04type\x18\x01 \x01(\t\x12Q\n\nattributes\x18\x02 \x03(\x0b\x32\x1f.tendermint.abci.EventAttributeB\x1c\xc8\xde\x1f\x00\xea\xde\x1f\x14\x61ttributes,omitempty";\n\x0e\x45ventAttribute\x12\x0b\n\x03key\x18\x01 \x01(\x0c\x12\r\n\x05value\x18\x02 \x01(\x0c\x12\r\n\x05index\x18\x03 \x01(\x08"o\n\x08TxResult\x12\x0e\n\x06height\x18\x01 \x01(\x03\x12\r\n\x05index\x18\x02 \x01(\r\x12\n\n\x02tx\x18\x03 \x01(\x0c\x12\x38\n\x06result\x18\x04 \x01(\x0b\x32".tendermint.abci.ResponseDeliverTxB\x04\xc8\xde\x1f\x00"+\n\tValidator\x12\x0f\n\x07\x61\x64\x64ress\x18\x01 \x01(\x0c\x12\r\n\x05power\x18\x03 \x01(\x03"U\n\x0fValidatorUpdate\x12\x33\n\x07pub_key\x18\x01 \x01(\x0b\x32\x1c.tendermint.crypto.PublicKeyB\x04\xc8\xde\x1f\x00\x12\r\n\x05power\x18\x02 \x01(\x03"Z\n\x08VoteInfo\x12\x33\n\tvalidator\x18\x01 \x01(\x0b\x32\x1a.tendermint.abci.ValidatorB\x04\xc8\xde\x1f\x00\x12\x19\n\x11signed_last_block\x18\x02 \x01(\x08"\xcc\x01\n\x08\x45vidence\x12+\n\x04type\x18\x01 \x01(\x0e\x32\x1d.tendermint.abci.EvidenceType\x12\x33\n\tvalidator\x18\x02 \x01(\x0b\x32\x1a.tendermint.abci.ValidatorB\x04\xc8\xde\x1f\x00\x12\x0e\n\x06height\x18\x03 \x01(\x03\x12\x32\n\x04time\x18\x04 \x01(\x0b\x32\x1a.google.protobuf.TimestampB\x08\xc8\xde\x1f\x00\x90\xdf\x1f\x01\x12\x1a\n\x12total_voting_power\x18\x05 \x01(\x03"Z\n\x08Snapshot\x12\x0e\n\x06height\x18\x01 \x01(\x04\x12\x0e\n\x06\x66ormat\x18\x02 \x01(\r\x12\x0e\n\x06\x63hunks\x18\x03 \x01(\r\x12\x0c\n\x04hash\x18\x04 \x01(\x0c\x12\x10\n\x08metadata\x18\x05 \x01(\x0c*9\n\x0b\x43heckTxType\x12\x10\n\x03NEW\x10\x00\x1a\x07\x8a\x9d \x03New\x12\x18\n\x07RECHECK\x10\x01\x1a\x0b\x8a\x9d \x07Recheck*H\n\x0c\x45videnceType\x12\x0b\n\x07UNKNOWN\x10\x00\x12\x12\n\x0e\x44UPLICATE_VOTE\x10\x01\x12\x17\n\x13LIGHT_CLIENT_ATTACK\x10\x02\x32\x83\n\n\x0f\x41\x42\x43IApplication\x12\x43\n\x04\x45\x63ho\x12\x1c.tendermint.abci.RequestEcho\x1a\x1d.tendermint.abci.ResponseEcho\x12\x46\n\x05\x46lush\x12\x1d.tendermint.abci.RequestFlush\x1a\x1e.tendermint.abci.ResponseFlush\x12\x43\n\x04Info\x12\x1c.tendermint.abci.RequestInfo\x1a\x1d.tendermint.abci.ResponseInfo\x12R\n\tSetOption\x12!.tendermint.abci.RequestSetOption\x1a".tendermint.abci.ResponseSetOption\x12R\n\tDeliverTx\x12!.tendermint.abci.RequestDeliverTx\x1a".tendermint.abci.ResponseDeliverTx\x12L\n\x07\x43heckTx\x12\x1f.tendermint.abci.RequestCheckTx\x1a .tendermint.abci.ResponseCheckTx\x12\x46\n\x05Query\x12\x1d.tendermint.abci.RequestQuery\x1a\x1e.tendermint.abci.ResponseQuery\x12I\n\x06\x43ommit\x12\x1e.tendermint.abci.RequestCommit\x1a\x1f.tendermint.abci.ResponseCommit\x12R\n\tInitChain\x12!.tendermint.abci.RequestInitChain\x1a".tendermint.abci.ResponseInitChain\x12U\n\nBeginBlock\x12".tendermint.abci.RequestBeginBlock\x1a#.tendermint.abci.ResponseBeginBlock\x12O\n\x08\x45ndBlock\x12 .tendermint.abci.RequestEndBlock\x1a!.tendermint.abci.ResponseEndBlock\x12^\n\rListSnapshots\x12%.tendermint.abci.RequestListSnapshots\x1a&.tendermint.abci.ResponseListSnapshots\x12^\n\rOfferSnapshot\x12%.tendermint.abci.RequestOfferSnapshot\x1a&.tendermint.abci.ResponseOfferSnapshot\x12j\n\x11LoadSnapshotChunk\x12).tendermint.abci.RequestLoadSnapshotChunk\x1a*.tendermint.abci.ResponseLoadSnapshotChunk\x12m\n\x12\x41pplySnapshotChunk\x12*.tendermint.abci.RequestApplySnapshotChunk\x1a+.tendermint.abci.ResponseApplySnapshotChunkB-Z+github.com/tendermint/tendermint/abci/typesb\x06proto3', - dependencies=[ - tendermint_dot_crypto_dot_proof__pb2.DESCRIPTOR, - tendermint_dot_types_dot_types__pb2.DESCRIPTOR, - tendermint_dot_crypto_dot_keys__pb2.DESCRIPTOR, - tendermint_dot_types_dot_params__pb2.DESCRIPTOR, - google_dot_protobuf_dot_timestamp__pb2.DESCRIPTOR, - gogoproto_dot_gogo__pb2.DESCRIPTOR, - ], -) - -_CHECKTXTYPE = _descriptor.EnumDescriptor( - name="CheckTxType", - full_name="tendermint.abci.CheckTxType", - filename=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - values=[ - _descriptor.EnumValueDescriptor( - name="NEW", - index=0, - number=0, - serialized_options=b"\212\235 \003New", - type=None, - create_key=_descriptor._internal_create_key, - ), - _descriptor.EnumValueDescriptor( - name="RECHECK", - index=1, - number=1, - serialized_options=b"\212\235 \007Recheck", - type=None, - create_key=_descriptor._internal_create_key, - ), - ], - containing_type=None, - serialized_options=None, - serialized_start=6314, - serialized_end=6371, -) -_sym_db.RegisterEnumDescriptor(_CHECKTXTYPE) - -CheckTxType = enum_type_wrapper.EnumTypeWrapper(_CHECKTXTYPE) -_EVIDENCETYPE = _descriptor.EnumDescriptor( - name="EvidenceType", - full_name="tendermint.abci.EvidenceType", - filename=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - values=[ - _descriptor.EnumValueDescriptor( - name="UNKNOWN", - index=0, - number=0, - serialized_options=None, - type=None, - create_key=_descriptor._internal_create_key, - ), - _descriptor.EnumValueDescriptor( - name="DUPLICATE_VOTE", - index=1, - number=1, - serialized_options=None, - type=None, - create_key=_descriptor._internal_create_key, - ), - _descriptor.EnumValueDescriptor( - name="LIGHT_CLIENT_ATTACK", - index=2, - number=2, - serialized_options=None, - type=None, - create_key=_descriptor._internal_create_key, - ), - ], - containing_type=None, - serialized_options=None, - serialized_start=6373, - serialized_end=6445, -) -_sym_db.RegisterEnumDescriptor(_EVIDENCETYPE) - -EvidenceType = enum_type_wrapper.EnumTypeWrapper(_EVIDENCETYPE) -NEW = 0 -RECHECK = 1 -UNKNOWN = 0 -DUPLICATE_VOTE = 1 -LIGHT_CLIENT_ATTACK = 2 - - -_RESPONSEOFFERSNAPSHOT_RESULT = _descriptor.EnumDescriptor( - name="Result", - full_name="tendermint.abci.ResponseOfferSnapshot.Result", - filename=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - values=[ - _descriptor.EnumValueDescriptor( - name="UNKNOWN", - index=0, - number=0, - serialized_options=None, - type=None, - create_key=_descriptor._internal_create_key, - ), - _descriptor.EnumValueDescriptor( - name="ACCEPT", - index=1, - number=1, - serialized_options=None, - type=None, - create_key=_descriptor._internal_create_key, - ), - _descriptor.EnumValueDescriptor( - name="ABORT", - index=2, - number=2, - serialized_options=None, - type=None, - create_key=_descriptor._internal_create_key, - ), - _descriptor.EnumValueDescriptor( - name="REJECT", - index=3, - number=3, - serialized_options=None, - type=None, - create_key=_descriptor._internal_create_key, - ), - _descriptor.EnumValueDescriptor( - name="REJECT_FORMAT", - index=4, - number=4, - serialized_options=None, - type=None, - create_key=_descriptor._internal_create_key, - ), - _descriptor.EnumValueDescriptor( - name="REJECT_SENDER", - index=5, - number=5, - serialized_options=None, - type=None, - create_key=_descriptor._internal_create_key, - ), - ], - containing_type=None, - serialized_options=None, - serialized_start=4773, - serialized_end=4867, -) -_sym_db.RegisterEnumDescriptor(_RESPONSEOFFERSNAPSHOT_RESULT) - -_RESPONSEAPPLYSNAPSHOTCHUNK_RESULT = _descriptor.EnumDescriptor( - name="Result", - full_name="tendermint.abci.ResponseApplySnapshotChunk.Result", - filename=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - values=[ - _descriptor.EnumValueDescriptor( - name="UNKNOWN", - index=0, - number=0, - serialized_options=None, - type=None, - create_key=_descriptor._internal_create_key, - ), - _descriptor.EnumValueDescriptor( - name="ACCEPT", - index=1, - number=1, - serialized_options=None, - type=None, - create_key=_descriptor._internal_create_key, - ), - _descriptor.EnumValueDescriptor( - name="ABORT", - index=2, - number=2, - serialized_options=None, - type=None, - create_key=_descriptor._internal_create_key, - ), - _descriptor.EnumValueDescriptor( - name="RETRY", - index=3, - number=3, - serialized_options=None, - type=None, - create_key=_descriptor._internal_create_key, - ), - _descriptor.EnumValueDescriptor( - name="RETRY_SNAPSHOT", - index=4, - number=4, - serialized_options=None, - type=None, - create_key=_descriptor._internal_create_key, - ), - _descriptor.EnumValueDescriptor( - name="REJECT_SNAPSHOT", - index=5, - number=5, - serialized_options=None, - type=None, - create_key=_descriptor._internal_create_key, - ), - ], - containing_type=None, - serialized_options=None, - serialized_start=5060, - serialized_end=5156, -) -_sym_db.RegisterEnumDescriptor(_RESPONSEAPPLYSNAPSHOTCHUNK_RESULT) - - -_REQUEST = _descriptor.Descriptor( - name="Request", - full_name="tendermint.abci.Request", - filename=None, - file=DESCRIPTOR, - containing_type=None, - create_key=_descriptor._internal_create_key, - fields=[ - _descriptor.FieldDescriptor( - name="echo", - full_name="tendermint.abci.Request.echo", - index=0, - number=1, - type=11, - cpp_type=10, - label=1, - has_default_value=False, - default_value=None, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="flush", - full_name="tendermint.abci.Request.flush", - index=1, - number=2, - type=11, - cpp_type=10, - label=1, - has_default_value=False, - default_value=None, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="info", - full_name="tendermint.abci.Request.info", - index=2, - number=3, - type=11, - cpp_type=10, - label=1, - has_default_value=False, - default_value=None, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="set_option", - full_name="tendermint.abci.Request.set_option", - index=3, - number=4, - type=11, - cpp_type=10, - label=1, - has_default_value=False, - default_value=None, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="init_chain", - full_name="tendermint.abci.Request.init_chain", - index=4, - number=5, - type=11, - cpp_type=10, - label=1, - has_default_value=False, - default_value=None, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="query", - full_name="tendermint.abci.Request.query", - index=5, - number=6, - type=11, - cpp_type=10, - label=1, - has_default_value=False, - default_value=None, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="begin_block", - full_name="tendermint.abci.Request.begin_block", - index=6, - number=7, - type=11, - cpp_type=10, - label=1, - has_default_value=False, - default_value=None, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="check_tx", - full_name="tendermint.abci.Request.check_tx", - index=7, - number=8, - type=11, - cpp_type=10, - label=1, - has_default_value=False, - default_value=None, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="deliver_tx", - full_name="tendermint.abci.Request.deliver_tx", - index=8, - number=9, - type=11, - cpp_type=10, - label=1, - has_default_value=False, - default_value=None, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="end_block", - full_name="tendermint.abci.Request.end_block", - index=9, - number=10, - type=11, - cpp_type=10, - label=1, - has_default_value=False, - default_value=None, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="commit", - full_name="tendermint.abci.Request.commit", - index=10, - number=11, - type=11, - cpp_type=10, - label=1, - has_default_value=False, - default_value=None, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="list_snapshots", - full_name="tendermint.abci.Request.list_snapshots", - index=11, - number=12, - type=11, - cpp_type=10, - label=1, - has_default_value=False, - default_value=None, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="offer_snapshot", - full_name="tendermint.abci.Request.offer_snapshot", - index=12, - number=13, - type=11, - cpp_type=10, - label=1, - has_default_value=False, - default_value=None, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="load_snapshot_chunk", - full_name="tendermint.abci.Request.load_snapshot_chunk", - index=13, - number=14, - type=11, - cpp_type=10, - label=1, - has_default_value=False, - default_value=None, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="apply_snapshot_chunk", - full_name="tendermint.abci.Request.apply_snapshot_chunk", - index=14, - number=15, - type=11, - cpp_type=10, - label=1, - has_default_value=False, - default_value=None, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - ], - extensions=[], - nested_types=[], - enum_types=[], - serialized_options=None, - is_extendable=False, - syntax="proto3", - extension_ranges=[], - oneofs=[ - _descriptor.OneofDescriptor( - name="value", - full_name="tendermint.abci.Request.value", - index=0, - containing_type=None, - create_key=_descriptor._internal_create_key, - fields=[], - ), - ], - serialized_start=226, - serialized_end=1100, -) - - -_REQUESTECHO = _descriptor.Descriptor( - name="RequestEcho", - full_name="tendermint.abci.RequestEcho", - filename=None, - file=DESCRIPTOR, - containing_type=None, - create_key=_descriptor._internal_create_key, - fields=[ - _descriptor.FieldDescriptor( - name="message", - full_name="tendermint.abci.RequestEcho.message", - index=0, - number=1, - type=9, - cpp_type=9, - label=1, - has_default_value=False, - default_value=b"".decode("utf-8"), - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - ], - extensions=[], - nested_types=[], - enum_types=[], - serialized_options=None, - is_extendable=False, - syntax="proto3", - extension_ranges=[], - oneofs=[], - serialized_start=1102, - serialized_end=1132, -) - - -_REQUESTFLUSH = _descriptor.Descriptor( - name="RequestFlush", - full_name="tendermint.abci.RequestFlush", - filename=None, - file=DESCRIPTOR, - containing_type=None, - create_key=_descriptor._internal_create_key, - fields=[], - extensions=[], - nested_types=[], - enum_types=[], - serialized_options=None, - is_extendable=False, - syntax="proto3", - extension_ranges=[], - oneofs=[], - serialized_start=1134, - serialized_end=1148, -) - - -_REQUESTINFO = _descriptor.Descriptor( - name="RequestInfo", - full_name="tendermint.abci.RequestInfo", - filename=None, - file=DESCRIPTOR, - containing_type=None, - create_key=_descriptor._internal_create_key, - fields=[ - _descriptor.FieldDescriptor( - name="version", - full_name="tendermint.abci.RequestInfo.version", - index=0, - number=1, - type=9, - cpp_type=9, - label=1, - has_default_value=False, - default_value=b"".decode("utf-8"), - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="block_version", - full_name="tendermint.abci.RequestInfo.block_version", - index=1, - number=2, - type=4, - cpp_type=4, - label=1, - has_default_value=False, - default_value=0, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="p2p_version", - full_name="tendermint.abci.RequestInfo.p2p_version", - index=2, - number=3, - type=4, - cpp_type=4, - label=1, - has_default_value=False, - default_value=0, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - ], - extensions=[], - nested_types=[], - enum_types=[], - serialized_options=None, - is_extendable=False, - syntax="proto3", - extension_ranges=[], - oneofs=[], - serialized_start=1150, - serialized_end=1224, -) - - -_REQUESTSETOPTION = _descriptor.Descriptor( - name="RequestSetOption", - full_name="tendermint.abci.RequestSetOption", - filename=None, - file=DESCRIPTOR, - containing_type=None, - create_key=_descriptor._internal_create_key, - fields=[ - _descriptor.FieldDescriptor( - name="key", - full_name="tendermint.abci.RequestSetOption.key", - index=0, - number=1, - type=9, - cpp_type=9, - label=1, - has_default_value=False, - default_value=b"".decode("utf-8"), - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="value", - full_name="tendermint.abci.RequestSetOption.value", - index=1, - number=2, - type=9, - cpp_type=9, - label=1, - has_default_value=False, - default_value=b"".decode("utf-8"), - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - ], - extensions=[], - nested_types=[], - enum_types=[], - serialized_options=None, - is_extendable=False, - syntax="proto3", - extension_ranges=[], - oneofs=[], - serialized_start=1226, - serialized_end=1272, -) - - -_REQUESTINITCHAIN = _descriptor.Descriptor( - name="RequestInitChain", - full_name="tendermint.abci.RequestInitChain", - filename=None, - file=DESCRIPTOR, - containing_type=None, - create_key=_descriptor._internal_create_key, - fields=[ - _descriptor.FieldDescriptor( - name="time", - full_name="tendermint.abci.RequestInitChain.time", - index=0, - number=1, - type=11, - cpp_type=10, - label=1, - has_default_value=False, - default_value=None, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=b"\310\336\037\000\220\337\037\001", - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="chain_id", - full_name="tendermint.abci.RequestInitChain.chain_id", - index=1, - number=2, - type=9, - cpp_type=9, - label=1, - has_default_value=False, - default_value=b"".decode("utf-8"), - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="consensus_params", - full_name="tendermint.abci.RequestInitChain.consensus_params", - index=2, - number=3, - type=11, - cpp_type=10, - label=1, - has_default_value=False, - default_value=None, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="validators", - full_name="tendermint.abci.RequestInitChain.validators", - index=3, - number=4, - type=11, - cpp_type=10, - label=3, - has_default_value=False, - default_value=[], - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=b"\310\336\037\000", - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="app_state_bytes", - full_name="tendermint.abci.RequestInitChain.app_state_bytes", - index=4, - number=5, - type=12, - cpp_type=9, - label=1, - has_default_value=False, - default_value=b"", - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="initial_height", - full_name="tendermint.abci.RequestInitChain.initial_height", - index=5, - number=6, - type=3, - cpp_type=2, - label=1, - has_default_value=False, - default_value=0, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - ], - extensions=[], - nested_types=[], - enum_types=[], - serialized_options=None, - is_extendable=False, - syntax="proto3", - extension_ranges=[], - oneofs=[], - serialized_start=1275, - serialized_end=1532, -) - - -_REQUESTQUERY = _descriptor.Descriptor( - name="RequestQuery", - full_name="tendermint.abci.RequestQuery", - filename=None, - file=DESCRIPTOR, - containing_type=None, - create_key=_descriptor._internal_create_key, - fields=[ - _descriptor.FieldDescriptor( - name="data", - full_name="tendermint.abci.RequestQuery.data", - index=0, - number=1, - type=12, - cpp_type=9, - label=1, - has_default_value=False, - default_value=b"", - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="path", - full_name="tendermint.abci.RequestQuery.path", - index=1, - number=2, - type=9, - cpp_type=9, - label=1, - has_default_value=False, - default_value=b"".decode("utf-8"), - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="height", - full_name="tendermint.abci.RequestQuery.height", - index=2, - number=3, - type=3, - cpp_type=2, - label=1, - has_default_value=False, - default_value=0, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="prove", - full_name="tendermint.abci.RequestQuery.prove", - index=3, - number=4, - type=8, - cpp_type=7, - label=1, - has_default_value=False, - default_value=False, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - ], - extensions=[], - nested_types=[], - enum_types=[], - serialized_options=None, - is_extendable=False, - syntax="proto3", - extension_ranges=[], - oneofs=[], - serialized_start=1534, - serialized_end=1607, -) - - -_REQUESTBEGINBLOCK = _descriptor.Descriptor( - name="RequestBeginBlock", - full_name="tendermint.abci.RequestBeginBlock", - filename=None, - file=DESCRIPTOR, - containing_type=None, - create_key=_descriptor._internal_create_key, - fields=[ - _descriptor.FieldDescriptor( - name="hash", - full_name="tendermint.abci.RequestBeginBlock.hash", - index=0, - number=1, - type=12, - cpp_type=9, - label=1, - has_default_value=False, - default_value=b"", - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="header", - full_name="tendermint.abci.RequestBeginBlock.header", - index=1, - number=2, - type=11, - cpp_type=10, - label=1, - has_default_value=False, - default_value=None, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=b"\310\336\037\000", - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="last_commit_info", - full_name="tendermint.abci.RequestBeginBlock.last_commit_info", - index=2, - number=3, - type=11, - cpp_type=10, - label=1, - has_default_value=False, - default_value=None, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=b"\310\336\037\000", - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="byzantine_validators", - full_name="tendermint.abci.RequestBeginBlock.byzantine_validators", - index=3, - number=4, - type=11, - cpp_type=10, - label=3, - has_default_value=False, - default_value=[], - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=b"\310\336\037\000", - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - ], - extensions=[], - nested_types=[], - enum_types=[], - serialized_options=None, - is_extendable=False, - syntax="proto3", - extension_ranges=[], - oneofs=[], - serialized_start=1610, - serialized_end=1819, -) - - -_REQUESTCHECKTX = _descriptor.Descriptor( - name="RequestCheckTx", - full_name="tendermint.abci.RequestCheckTx", - filename=None, - file=DESCRIPTOR, - containing_type=None, - create_key=_descriptor._internal_create_key, - fields=[ - _descriptor.FieldDescriptor( - name="tx", - full_name="tendermint.abci.RequestCheckTx.tx", - index=0, - number=1, - type=12, - cpp_type=9, - label=1, - has_default_value=False, - default_value=b"", - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="type", - full_name="tendermint.abci.RequestCheckTx.type", - index=1, - number=2, - type=14, - cpp_type=8, - label=1, - has_default_value=False, - default_value=0, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - ], - extensions=[], - nested_types=[], - enum_types=[], - serialized_options=None, - is_extendable=False, - syntax="proto3", - extension_ranges=[], - oneofs=[], - serialized_start=1821, - serialized_end=1893, -) - - -_REQUESTDELIVERTX = _descriptor.Descriptor( - name="RequestDeliverTx", - full_name="tendermint.abci.RequestDeliverTx", - filename=None, - file=DESCRIPTOR, - containing_type=None, - create_key=_descriptor._internal_create_key, - fields=[ - _descriptor.FieldDescriptor( - name="tx", - full_name="tendermint.abci.RequestDeliverTx.tx", - index=0, - number=1, - type=12, - cpp_type=9, - label=1, - has_default_value=False, - default_value=b"", - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - ], - extensions=[], - nested_types=[], - enum_types=[], - serialized_options=None, - is_extendable=False, - syntax="proto3", - extension_ranges=[], - oneofs=[], - serialized_start=1895, - serialized_end=1925, -) - - -_REQUESTENDBLOCK = _descriptor.Descriptor( - name="RequestEndBlock", - full_name="tendermint.abci.RequestEndBlock", - filename=None, - file=DESCRIPTOR, - containing_type=None, - create_key=_descriptor._internal_create_key, - fields=[ - _descriptor.FieldDescriptor( - name="height", - full_name="tendermint.abci.RequestEndBlock.height", - index=0, - number=1, - type=3, - cpp_type=2, - label=1, - has_default_value=False, - default_value=0, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - ], - extensions=[], - nested_types=[], - enum_types=[], - serialized_options=None, - is_extendable=False, - syntax="proto3", - extension_ranges=[], - oneofs=[], - serialized_start=1927, - serialized_end=1960, -) - - -_REQUESTCOMMIT = _descriptor.Descriptor( - name="RequestCommit", - full_name="tendermint.abci.RequestCommit", - filename=None, - file=DESCRIPTOR, - containing_type=None, - create_key=_descriptor._internal_create_key, - fields=[], - extensions=[], - nested_types=[], - enum_types=[], - serialized_options=None, - is_extendable=False, - syntax="proto3", - extension_ranges=[], - oneofs=[], - serialized_start=1962, - serialized_end=1977, -) - - -_REQUESTLISTSNAPSHOTS = _descriptor.Descriptor( - name="RequestListSnapshots", - full_name="tendermint.abci.RequestListSnapshots", - filename=None, - file=DESCRIPTOR, - containing_type=None, - create_key=_descriptor._internal_create_key, - fields=[], - extensions=[], - nested_types=[], - enum_types=[], - serialized_options=None, - is_extendable=False, - syntax="proto3", - extension_ranges=[], - oneofs=[], - serialized_start=1979, - serialized_end=2001, -) - - -_REQUESTOFFERSNAPSHOT = _descriptor.Descriptor( - name="RequestOfferSnapshot", - full_name="tendermint.abci.RequestOfferSnapshot", - filename=None, - file=DESCRIPTOR, - containing_type=None, - create_key=_descriptor._internal_create_key, - fields=[ - _descriptor.FieldDescriptor( - name="snapshot", - full_name="tendermint.abci.RequestOfferSnapshot.snapshot", - index=0, - number=1, - type=11, - cpp_type=10, - label=1, - has_default_value=False, - default_value=None, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="app_hash", - full_name="tendermint.abci.RequestOfferSnapshot.app_hash", - index=1, - number=2, - type=12, - cpp_type=9, - label=1, - has_default_value=False, - default_value=b"", - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - ], - extensions=[], - nested_types=[], - enum_types=[], - serialized_options=None, - is_extendable=False, - syntax="proto3", - extension_ranges=[], - oneofs=[], - serialized_start=2003, - serialized_end=2088, -) - - -_REQUESTLOADSNAPSHOTCHUNK = _descriptor.Descriptor( - name="RequestLoadSnapshotChunk", - full_name="tendermint.abci.RequestLoadSnapshotChunk", - filename=None, - file=DESCRIPTOR, - containing_type=None, - create_key=_descriptor._internal_create_key, - fields=[ - _descriptor.FieldDescriptor( - name="height", - full_name="tendermint.abci.RequestLoadSnapshotChunk.height", - index=0, - number=1, - type=4, - cpp_type=4, - label=1, - has_default_value=False, - default_value=0, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="format", - full_name="tendermint.abci.RequestLoadSnapshotChunk.format", - index=1, - number=2, - type=13, - cpp_type=3, - label=1, - has_default_value=False, - default_value=0, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="chunk", - full_name="tendermint.abci.RequestLoadSnapshotChunk.chunk", - index=2, - number=3, - type=13, - cpp_type=3, - label=1, - has_default_value=False, - default_value=0, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - ], - extensions=[], - nested_types=[], - enum_types=[], - serialized_options=None, - is_extendable=False, - syntax="proto3", - extension_ranges=[], - oneofs=[], - serialized_start=2090, - serialized_end=2163, -) - - -_REQUESTAPPLYSNAPSHOTCHUNK = _descriptor.Descriptor( - name="RequestApplySnapshotChunk", - full_name="tendermint.abci.RequestApplySnapshotChunk", - filename=None, - file=DESCRIPTOR, - containing_type=None, - create_key=_descriptor._internal_create_key, - fields=[ - _descriptor.FieldDescriptor( - name="index", - full_name="tendermint.abci.RequestApplySnapshotChunk.index", - index=0, - number=1, - type=13, - cpp_type=3, - label=1, - has_default_value=False, - default_value=0, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="chunk", - full_name="tendermint.abci.RequestApplySnapshotChunk.chunk", - index=1, - number=2, - type=12, - cpp_type=9, - label=1, - has_default_value=False, - default_value=b"", - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="sender", - full_name="tendermint.abci.RequestApplySnapshotChunk.sender", - index=2, - number=3, - type=9, - cpp_type=9, - label=1, - has_default_value=False, - default_value=b"".decode("utf-8"), - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - ], - extensions=[], - nested_types=[], - enum_types=[], - serialized_options=None, - is_extendable=False, - syntax="proto3", - extension_ranges=[], - oneofs=[], - serialized_start=2165, - serialized_end=2238, -) - - -_RESPONSE = _descriptor.Descriptor( - name="Response", - full_name="tendermint.abci.Response", - filename=None, - file=DESCRIPTOR, - containing_type=None, - create_key=_descriptor._internal_create_key, - fields=[ - _descriptor.FieldDescriptor( - name="exception", - full_name="tendermint.abci.Response.exception", - index=0, - number=1, - type=11, - cpp_type=10, - label=1, - has_default_value=False, - default_value=None, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="echo", - full_name="tendermint.abci.Response.echo", - index=1, - number=2, - type=11, - cpp_type=10, - label=1, - has_default_value=False, - default_value=None, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="flush", - full_name="tendermint.abci.Response.flush", - index=2, - number=3, - type=11, - cpp_type=10, - label=1, - has_default_value=False, - default_value=None, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="info", - full_name="tendermint.abci.Response.info", - index=3, - number=4, - type=11, - cpp_type=10, - label=1, - has_default_value=False, - default_value=None, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="set_option", - full_name="tendermint.abci.Response.set_option", - index=4, - number=5, - type=11, - cpp_type=10, - label=1, - has_default_value=False, - default_value=None, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="init_chain", - full_name="tendermint.abci.Response.init_chain", - index=5, - number=6, - type=11, - cpp_type=10, - label=1, - has_default_value=False, - default_value=None, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="query", - full_name="tendermint.abci.Response.query", - index=6, - number=7, - type=11, - cpp_type=10, - label=1, - has_default_value=False, - default_value=None, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="begin_block", - full_name="tendermint.abci.Response.begin_block", - index=7, - number=8, - type=11, - cpp_type=10, - label=1, - has_default_value=False, - default_value=None, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="check_tx", - full_name="tendermint.abci.Response.check_tx", - index=8, - number=9, - type=11, - cpp_type=10, - label=1, - has_default_value=False, - default_value=None, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="deliver_tx", - full_name="tendermint.abci.Response.deliver_tx", - index=9, - number=10, - type=11, - cpp_type=10, - label=1, - has_default_value=False, - default_value=None, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="end_block", - full_name="tendermint.abci.Response.end_block", - index=10, - number=11, - type=11, - cpp_type=10, - label=1, - has_default_value=False, - default_value=None, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="commit", - full_name="tendermint.abci.Response.commit", - index=11, - number=12, - type=11, - cpp_type=10, - label=1, - has_default_value=False, - default_value=None, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="list_snapshots", - full_name="tendermint.abci.Response.list_snapshots", - index=12, - number=13, - type=11, - cpp_type=10, - label=1, - has_default_value=False, - default_value=None, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="offer_snapshot", - full_name="tendermint.abci.Response.offer_snapshot", - index=13, - number=14, - type=11, - cpp_type=10, - label=1, - has_default_value=False, - default_value=None, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="load_snapshot_chunk", - full_name="tendermint.abci.Response.load_snapshot_chunk", - index=14, - number=15, - type=11, - cpp_type=10, - label=1, - has_default_value=False, - default_value=None, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="apply_snapshot_chunk", - full_name="tendermint.abci.Response.apply_snapshot_chunk", - index=15, - number=16, - type=11, - cpp_type=10, - label=1, - has_default_value=False, - default_value=None, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - ], - extensions=[], - nested_types=[], - enum_types=[], - serialized_options=None, - is_extendable=False, - syntax="proto3", - extension_ranges=[], - oneofs=[ - _descriptor.OneofDescriptor( - name="value", - full_name="tendermint.abci.Response.value", - index=0, - containing_type=None, - create_key=_descriptor._internal_create_key, - fields=[], - ), - ], - serialized_start=2241, - serialized_end=3188, -) - - -_RESPONSEEXCEPTION = _descriptor.Descriptor( - name="ResponseException", - full_name="tendermint.abci.ResponseException", - filename=None, - file=DESCRIPTOR, - containing_type=None, - create_key=_descriptor._internal_create_key, - fields=[ - _descriptor.FieldDescriptor( - name="error", - full_name="tendermint.abci.ResponseException.error", - index=0, - number=1, - type=9, - cpp_type=9, - label=1, - has_default_value=False, - default_value=b"".decode("utf-8"), - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - ], - extensions=[], - nested_types=[], - enum_types=[], - serialized_options=None, - is_extendable=False, - syntax="proto3", - extension_ranges=[], - oneofs=[], - serialized_start=3190, - serialized_end=3224, -) - - -_RESPONSEECHO = _descriptor.Descriptor( - name="ResponseEcho", - full_name="tendermint.abci.ResponseEcho", - filename=None, - file=DESCRIPTOR, - containing_type=None, - create_key=_descriptor._internal_create_key, - fields=[ - _descriptor.FieldDescriptor( - name="message", - full_name="tendermint.abci.ResponseEcho.message", - index=0, - number=1, - type=9, - cpp_type=9, - label=1, - has_default_value=False, - default_value=b"".decode("utf-8"), - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - ], - extensions=[], - nested_types=[], - enum_types=[], - serialized_options=None, - is_extendable=False, - syntax="proto3", - extension_ranges=[], - oneofs=[], - serialized_start=3226, - serialized_end=3257, -) - - -_RESPONSEFLUSH = _descriptor.Descriptor( - name="ResponseFlush", - full_name="tendermint.abci.ResponseFlush", - filename=None, - file=DESCRIPTOR, - containing_type=None, - create_key=_descriptor._internal_create_key, - fields=[], - extensions=[], - nested_types=[], - enum_types=[], - serialized_options=None, - is_extendable=False, - syntax="proto3", - extension_ranges=[], - oneofs=[], - serialized_start=3259, - serialized_end=3274, -) - - -_RESPONSEINFO = _descriptor.Descriptor( - name="ResponseInfo", - full_name="tendermint.abci.ResponseInfo", - filename=None, - file=DESCRIPTOR, - containing_type=None, - create_key=_descriptor._internal_create_key, - fields=[ - _descriptor.FieldDescriptor( - name="data", - full_name="tendermint.abci.ResponseInfo.data", - index=0, - number=1, - type=9, - cpp_type=9, - label=1, - has_default_value=False, - default_value=b"".decode("utf-8"), - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="version", - full_name="tendermint.abci.ResponseInfo.version", - index=1, - number=2, - type=9, - cpp_type=9, - label=1, - has_default_value=False, - default_value=b"".decode("utf-8"), - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="app_version", - full_name="tendermint.abci.ResponseInfo.app_version", - index=2, - number=3, - type=4, - cpp_type=4, - label=1, - has_default_value=False, - default_value=0, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="last_block_height", - full_name="tendermint.abci.ResponseInfo.last_block_height", - index=3, - number=4, - type=3, - cpp_type=2, - label=1, - has_default_value=False, - default_value=0, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="last_block_app_hash", - full_name="tendermint.abci.ResponseInfo.last_block_app_hash", - index=4, - number=5, - type=12, - cpp_type=9, - label=1, - has_default_value=False, - default_value=b"", - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - ], - extensions=[], - nested_types=[], - enum_types=[], - serialized_options=None, - is_extendable=False, - syntax="proto3", - extension_ranges=[], - oneofs=[], - serialized_start=3276, - serialized_end=3398, -) - - -_RESPONSESETOPTION = _descriptor.Descriptor( - name="ResponseSetOption", - full_name="tendermint.abci.ResponseSetOption", - filename=None, - file=DESCRIPTOR, - containing_type=None, - create_key=_descriptor._internal_create_key, - fields=[ - _descriptor.FieldDescriptor( - name="code", - full_name="tendermint.abci.ResponseSetOption.code", - index=0, - number=1, - type=13, - cpp_type=3, - label=1, - has_default_value=False, - default_value=0, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="log", - full_name="tendermint.abci.ResponseSetOption.log", - index=1, - number=3, - type=9, - cpp_type=9, - label=1, - has_default_value=False, - default_value=b"".decode("utf-8"), - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="info", - full_name="tendermint.abci.ResponseSetOption.info", - index=2, - number=4, - type=9, - cpp_type=9, - label=1, - has_default_value=False, - default_value=b"".decode("utf-8"), - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - ], - extensions=[], - nested_types=[], - enum_types=[], - serialized_options=None, - is_extendable=False, - syntax="proto3", - extension_ranges=[], - oneofs=[], - serialized_start=3400, - serialized_end=3460, -) - - -_RESPONSEINITCHAIN = _descriptor.Descriptor( - name="ResponseInitChain", - full_name="tendermint.abci.ResponseInitChain", - filename=None, - file=DESCRIPTOR, - containing_type=None, - create_key=_descriptor._internal_create_key, - fields=[ - _descriptor.FieldDescriptor( - name="consensus_params", - full_name="tendermint.abci.ResponseInitChain.consensus_params", - index=0, - number=1, - type=11, - cpp_type=10, - label=1, - has_default_value=False, - default_value=None, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="validators", - full_name="tendermint.abci.ResponseInitChain.validators", - index=1, - number=2, - type=11, - cpp_type=10, - label=3, - has_default_value=False, - default_value=[], - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=b"\310\336\037\000", - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="app_hash", - full_name="tendermint.abci.ResponseInitChain.app_hash", - index=2, - number=3, - type=12, - cpp_type=9, - label=1, - has_default_value=False, - default_value=b"", - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - ], - extensions=[], - nested_types=[], - enum_types=[], - serialized_options=None, - is_extendable=False, - syntax="proto3", - extension_ranges=[], - oneofs=[], - serialized_start=3463, - serialized_end=3620, -) - - -_RESPONSEQUERY = _descriptor.Descriptor( - name="ResponseQuery", - full_name="tendermint.abci.ResponseQuery", - filename=None, - file=DESCRIPTOR, - containing_type=None, - create_key=_descriptor._internal_create_key, - fields=[ - _descriptor.FieldDescriptor( - name="code", - full_name="tendermint.abci.ResponseQuery.code", - index=0, - number=1, - type=13, - cpp_type=3, - label=1, - has_default_value=False, - default_value=0, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="log", - full_name="tendermint.abci.ResponseQuery.log", - index=1, - number=3, - type=9, - cpp_type=9, - label=1, - has_default_value=False, - default_value=b"".decode("utf-8"), - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="info", - full_name="tendermint.abci.ResponseQuery.info", - index=2, - number=4, - type=9, - cpp_type=9, - label=1, - has_default_value=False, - default_value=b"".decode("utf-8"), - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="index", - full_name="tendermint.abci.ResponseQuery.index", - index=3, - number=5, - type=3, - cpp_type=2, - label=1, - has_default_value=False, - default_value=0, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="key", - full_name="tendermint.abci.ResponseQuery.key", - index=4, - number=6, - type=12, - cpp_type=9, - label=1, - has_default_value=False, - default_value=b"", - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="value", - full_name="tendermint.abci.ResponseQuery.value", - index=5, - number=7, - type=12, - cpp_type=9, - label=1, - has_default_value=False, - default_value=b"", - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="proof_ops", - full_name="tendermint.abci.ResponseQuery.proof_ops", - index=6, - number=8, - type=11, - cpp_type=10, - label=1, - has_default_value=False, - default_value=None, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="height", - full_name="tendermint.abci.ResponseQuery.height", - index=7, - number=9, - type=3, - cpp_type=2, - label=1, - has_default_value=False, - default_value=0, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="codespace", - full_name="tendermint.abci.ResponseQuery.codespace", - index=8, - number=10, - type=9, - cpp_type=9, - label=1, - has_default_value=False, - default_value=b"".decode("utf-8"), - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - ], - extensions=[], - nested_types=[], - enum_types=[], - serialized_options=None, - is_extendable=False, - syntax="proto3", - extension_ranges=[], - oneofs=[], - serialized_start=3623, - serialized_end=3805, -) - - -_RESPONSEBEGINBLOCK = _descriptor.Descriptor( - name="ResponseBeginBlock", - full_name="tendermint.abci.ResponseBeginBlock", - filename=None, - file=DESCRIPTOR, - containing_type=None, - create_key=_descriptor._internal_create_key, - fields=[ - _descriptor.FieldDescriptor( - name="events", - full_name="tendermint.abci.ResponseBeginBlock.events", - index=0, - number=1, - type=11, - cpp_type=10, - label=3, - has_default_value=False, - default_value=[], - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=b"\310\336\037\000\352\336\037\020events,omitempty", - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - ], - extensions=[], - nested_types=[], - enum_types=[], - serialized_options=None, - is_extendable=False, - syntax="proto3", - extension_ranges=[], - oneofs=[], - serialized_start=3807, - serialized_end=3893, -) - - -_RESPONSECHECKTX = _descriptor.Descriptor( - name="ResponseCheckTx", - full_name="tendermint.abci.ResponseCheckTx", - filename=None, - file=DESCRIPTOR, - containing_type=None, - create_key=_descriptor._internal_create_key, - fields=[ - _descriptor.FieldDescriptor( - name="code", - full_name="tendermint.abci.ResponseCheckTx.code", - index=0, - number=1, - type=13, - cpp_type=3, - label=1, - has_default_value=False, - default_value=0, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="data", - full_name="tendermint.abci.ResponseCheckTx.data", - index=1, - number=2, - type=12, - cpp_type=9, - label=1, - has_default_value=False, - default_value=b"", - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="log", - full_name="tendermint.abci.ResponseCheckTx.log", - index=2, - number=3, - type=9, - cpp_type=9, - label=1, - has_default_value=False, - default_value=b"".decode("utf-8"), - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="info", - full_name="tendermint.abci.ResponseCheckTx.info", - index=3, - number=4, - type=9, - cpp_type=9, - label=1, - has_default_value=False, - default_value=b"".decode("utf-8"), - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="gas_wanted", - full_name="tendermint.abci.ResponseCheckTx.gas_wanted", - index=4, - number=5, - type=3, - cpp_type=2, - label=1, - has_default_value=False, - default_value=0, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - json_name="gas_wanted", - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="gas_used", - full_name="tendermint.abci.ResponseCheckTx.gas_used", - index=5, - number=6, - type=3, - cpp_type=2, - label=1, - has_default_value=False, - default_value=0, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - json_name="gas_used", - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="events", - full_name="tendermint.abci.ResponseCheckTx.events", - index=6, - number=7, - type=11, - cpp_type=10, - label=3, - has_default_value=False, - default_value=[], - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=b"\310\336\037\000\352\336\037\020events,omitempty", - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="codespace", - full_name="tendermint.abci.ResponseCheckTx.codespace", - index=7, - number=8, - type=9, - cpp_type=9, - label=1, - has_default_value=False, - default_value=b"".decode("utf-8"), - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - ], - extensions=[], - nested_types=[], - enum_types=[], - serialized_options=None, - is_extendable=False, - syntax="proto3", - extension_ranges=[], - oneofs=[], - serialized_start=3896, - serialized_end=4113, -) - - -_RESPONSEDELIVERTX = _descriptor.Descriptor( - name="ResponseDeliverTx", - full_name="tendermint.abci.ResponseDeliverTx", - filename=None, - file=DESCRIPTOR, - containing_type=None, - create_key=_descriptor._internal_create_key, - fields=[ - _descriptor.FieldDescriptor( - name="code", - full_name="tendermint.abci.ResponseDeliverTx.code", - index=0, - number=1, - type=13, - cpp_type=3, - label=1, - has_default_value=False, - default_value=0, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="data", - full_name="tendermint.abci.ResponseDeliverTx.data", - index=1, - number=2, - type=12, - cpp_type=9, - label=1, - has_default_value=False, - default_value=b"", - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="log", - full_name="tendermint.abci.ResponseDeliverTx.log", - index=2, - number=3, - type=9, - cpp_type=9, - label=1, - has_default_value=False, - default_value=b"".decode("utf-8"), - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="info", - full_name="tendermint.abci.ResponseDeliverTx.info", - index=3, - number=4, - type=9, - cpp_type=9, - label=1, - has_default_value=False, - default_value=b"".decode("utf-8"), - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="gas_wanted", - full_name="tendermint.abci.ResponseDeliverTx.gas_wanted", - index=4, - number=5, - type=3, - cpp_type=2, - label=1, - has_default_value=False, - default_value=0, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - json_name="gas_wanted", - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="gas_used", - full_name="tendermint.abci.ResponseDeliverTx.gas_used", - index=5, - number=6, - type=3, - cpp_type=2, - label=1, - has_default_value=False, - default_value=0, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - json_name="gas_used", - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="events", - full_name="tendermint.abci.ResponseDeliverTx.events", - index=6, - number=7, - type=11, - cpp_type=10, - label=3, - has_default_value=False, - default_value=[], - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=b"\310\336\037\000\352\336\037\020events,omitempty", - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="codespace", - full_name="tendermint.abci.ResponseDeliverTx.codespace", - index=7, - number=8, - type=9, - cpp_type=9, - label=1, - has_default_value=False, - default_value=b"".decode("utf-8"), - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - ], - extensions=[], - nested_types=[], - enum_types=[], - serialized_options=None, - is_extendable=False, - syntax="proto3", - extension_ranges=[], - oneofs=[], - serialized_start=4116, - serialized_end=4335, -) - - -_RESPONSEENDBLOCK = _descriptor.Descriptor( - name="ResponseEndBlock", - full_name="tendermint.abci.ResponseEndBlock", - filename=None, - file=DESCRIPTOR, - containing_type=None, - create_key=_descriptor._internal_create_key, - fields=[ - _descriptor.FieldDescriptor( - name="validator_updates", - full_name="tendermint.abci.ResponseEndBlock.validator_updates", - index=0, - number=1, - type=11, - cpp_type=10, - label=3, - has_default_value=False, - default_value=[], - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=b"\310\336\037\000", - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="consensus_param_updates", - full_name="tendermint.abci.ResponseEndBlock.consensus_param_updates", - index=1, - number=2, - type=11, - cpp_type=10, - label=1, - has_default_value=False, - default_value=None, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="events", - full_name="tendermint.abci.ResponseEndBlock.events", - index=2, - number=3, - type=11, - cpp_type=10, - label=3, - has_default_value=False, - default_value=[], - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=b"\310\336\037\000\352\336\037\020events,omitempty", - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - ], - extensions=[], - nested_types=[], - enum_types=[], - serialized_options=None, - is_extendable=False, - syntax="proto3", - extension_ranges=[], - oneofs=[], - serialized_start=4338, - serialized_end=4556, -) - - -_RESPONSECOMMIT = _descriptor.Descriptor( - name="ResponseCommit", - full_name="tendermint.abci.ResponseCommit", - filename=None, - file=DESCRIPTOR, - containing_type=None, - create_key=_descriptor._internal_create_key, - fields=[ - _descriptor.FieldDescriptor( - name="data", - full_name="tendermint.abci.ResponseCommit.data", - index=0, - number=2, - type=12, - cpp_type=9, - label=1, - has_default_value=False, - default_value=b"", - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="retain_height", - full_name="tendermint.abci.ResponseCommit.retain_height", - index=1, - number=3, - type=3, - cpp_type=2, - label=1, - has_default_value=False, - default_value=0, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - ], - extensions=[], - nested_types=[], - enum_types=[], - serialized_options=None, - is_extendable=False, - syntax="proto3", - extension_ranges=[], - oneofs=[], - serialized_start=4558, - serialized_end=4611, -) - - -_RESPONSELISTSNAPSHOTS = _descriptor.Descriptor( - name="ResponseListSnapshots", - full_name="tendermint.abci.ResponseListSnapshots", - filename=None, - file=DESCRIPTOR, - containing_type=None, - create_key=_descriptor._internal_create_key, - fields=[ - _descriptor.FieldDescriptor( - name="snapshots", - full_name="tendermint.abci.ResponseListSnapshots.snapshots", - index=0, - number=1, - type=11, - cpp_type=10, - label=3, - has_default_value=False, - default_value=[], - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - ], - extensions=[], - nested_types=[], - enum_types=[], - serialized_options=None, - is_extendable=False, - syntax="proto3", - extension_ranges=[], - oneofs=[], - serialized_start=4613, - serialized_end=4682, -) - - -_RESPONSEOFFERSNAPSHOT = _descriptor.Descriptor( - name="ResponseOfferSnapshot", - full_name="tendermint.abci.ResponseOfferSnapshot", - filename=None, - file=DESCRIPTOR, - containing_type=None, - create_key=_descriptor._internal_create_key, - fields=[ - _descriptor.FieldDescriptor( - name="result", - full_name="tendermint.abci.ResponseOfferSnapshot.result", - index=0, - number=1, - type=14, - cpp_type=8, - label=1, - has_default_value=False, - default_value=0, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - ], - extensions=[], - nested_types=[], - enum_types=[ - _RESPONSEOFFERSNAPSHOT_RESULT, - ], - serialized_options=None, - is_extendable=False, - syntax="proto3", - extension_ranges=[], - oneofs=[], - serialized_start=4685, - serialized_end=4867, -) - - -_RESPONSELOADSNAPSHOTCHUNK = _descriptor.Descriptor( - name="ResponseLoadSnapshotChunk", - full_name="tendermint.abci.ResponseLoadSnapshotChunk", - filename=None, - file=DESCRIPTOR, - containing_type=None, - create_key=_descriptor._internal_create_key, - fields=[ - _descriptor.FieldDescriptor( - name="chunk", - full_name="tendermint.abci.ResponseLoadSnapshotChunk.chunk", - index=0, - number=1, - type=12, - cpp_type=9, - label=1, - has_default_value=False, - default_value=b"", - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - ], - extensions=[], - nested_types=[], - enum_types=[], - serialized_options=None, - is_extendable=False, - syntax="proto3", - extension_ranges=[], - oneofs=[], - serialized_start=4869, - serialized_end=4911, -) - - -_RESPONSEAPPLYSNAPSHOTCHUNK = _descriptor.Descriptor( - name="ResponseApplySnapshotChunk", - full_name="tendermint.abci.ResponseApplySnapshotChunk", - filename=None, - file=DESCRIPTOR, - containing_type=None, - create_key=_descriptor._internal_create_key, - fields=[ - _descriptor.FieldDescriptor( - name="result", - full_name="tendermint.abci.ResponseApplySnapshotChunk.result", - index=0, - number=1, - type=14, - cpp_type=8, - label=1, - has_default_value=False, - default_value=0, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="refetch_chunks", - full_name="tendermint.abci.ResponseApplySnapshotChunk.refetch_chunks", - index=1, - number=2, - type=13, - cpp_type=3, - label=3, - has_default_value=False, - default_value=[], - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="reject_senders", - full_name="tendermint.abci.ResponseApplySnapshotChunk.reject_senders", - index=2, - number=3, - type=9, - cpp_type=9, - label=3, - has_default_value=False, - default_value=[], - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - ], - extensions=[], - nested_types=[], - enum_types=[ - _RESPONSEAPPLYSNAPSHOTCHUNK_RESULT, - ], - serialized_options=None, - is_extendable=False, - syntax="proto3", - extension_ranges=[], - oneofs=[], - serialized_start=4914, - serialized_end=5156, -) - - -_CONSENSUSPARAMS = _descriptor.Descriptor( - name="ConsensusParams", - full_name="tendermint.abci.ConsensusParams", - filename=None, - file=DESCRIPTOR, - containing_type=None, - create_key=_descriptor._internal_create_key, - fields=[ - _descriptor.FieldDescriptor( - name="block", - full_name="tendermint.abci.ConsensusParams.block", - index=0, - number=1, - type=11, - cpp_type=10, - label=1, - has_default_value=False, - default_value=None, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="evidence", - full_name="tendermint.abci.ConsensusParams.evidence", - index=1, - number=2, - type=11, - cpp_type=10, - label=1, - has_default_value=False, - default_value=None, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="validator", - full_name="tendermint.abci.ConsensusParams.validator", - index=2, - number=3, - type=11, - cpp_type=10, - label=1, - has_default_value=False, - default_value=None, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="version", - full_name="tendermint.abci.ConsensusParams.version", - index=3, - number=4, - type=11, - cpp_type=10, - label=1, - has_default_value=False, - default_value=None, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - ], - extensions=[], - nested_types=[], - enum_types=[], - serialized_options=None, - is_extendable=False, - syntax="proto3", - extension_ranges=[], - oneofs=[], - serialized_start=5159, - serialized_end=5377, -) - - -_BLOCKPARAMS = _descriptor.Descriptor( - name="BlockParams", - full_name="tendermint.abci.BlockParams", - filename=None, - file=DESCRIPTOR, - containing_type=None, - create_key=_descriptor._internal_create_key, - fields=[ - _descriptor.FieldDescriptor( - name="max_bytes", - full_name="tendermint.abci.BlockParams.max_bytes", - index=0, - number=1, - type=3, - cpp_type=2, - label=1, - has_default_value=False, - default_value=0, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="max_gas", - full_name="tendermint.abci.BlockParams.max_gas", - index=1, - number=2, - type=3, - cpp_type=2, - label=1, - has_default_value=False, - default_value=0, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - ], - extensions=[], - nested_types=[], - enum_types=[], - serialized_options=None, - is_extendable=False, - syntax="proto3", - extension_ranges=[], - oneofs=[], - serialized_start=5379, - serialized_end=5428, -) - - -_LASTCOMMITINFO = _descriptor.Descriptor( - name="LastCommitInfo", - full_name="tendermint.abci.LastCommitInfo", - filename=None, - file=DESCRIPTOR, - containing_type=None, - create_key=_descriptor._internal_create_key, - fields=[ - _descriptor.FieldDescriptor( - name="round", - full_name="tendermint.abci.LastCommitInfo.round", - index=0, - number=1, - type=5, - cpp_type=1, - label=1, - has_default_value=False, - default_value=0, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="votes", - full_name="tendermint.abci.LastCommitInfo.votes", - index=1, - number=2, - type=11, - cpp_type=10, - label=3, - has_default_value=False, - default_value=[], - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=b"\310\336\037\000", - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - ], - extensions=[], - nested_types=[], - enum_types=[], - serialized_options=None, - is_extendable=False, - syntax="proto3", - extension_ranges=[], - oneofs=[], - serialized_start=5430, - serialized_end=5509, -) - - -_EVENT = _descriptor.Descriptor( - name="Event", - full_name="tendermint.abci.Event", - filename=None, - file=DESCRIPTOR, - containing_type=None, - create_key=_descriptor._internal_create_key, - fields=[ - _descriptor.FieldDescriptor( - name="type", - full_name="tendermint.abci.Event.type", - index=0, - number=1, - type=9, - cpp_type=9, - label=1, - has_default_value=False, - default_value=b"".decode("utf-8"), - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="attributes", - full_name="tendermint.abci.Event.attributes", - index=1, - number=2, - type=11, - cpp_type=10, - label=3, - has_default_value=False, - default_value=[], - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=b"\310\336\037\000\352\336\037\024attributes,omitempty", - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - ], - extensions=[], - nested_types=[], - enum_types=[], - serialized_options=None, - is_extendable=False, - syntax="proto3", - extension_ranges=[], - oneofs=[], - serialized_start=5511, - serialized_end=5615, -) - - -_EVENTATTRIBUTE = _descriptor.Descriptor( - name="EventAttribute", - full_name="tendermint.abci.EventAttribute", - filename=None, - file=DESCRIPTOR, - containing_type=None, - create_key=_descriptor._internal_create_key, - fields=[ - _descriptor.FieldDescriptor( - name="key", - full_name="tendermint.abci.EventAttribute.key", - index=0, - number=1, - type=12, - cpp_type=9, - label=1, - has_default_value=False, - default_value=b"", - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="value", - full_name="tendermint.abci.EventAttribute.value", - index=1, - number=2, - type=12, - cpp_type=9, - label=1, - has_default_value=False, - default_value=b"", - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="index", - full_name="tendermint.abci.EventAttribute.index", - index=2, - number=3, - type=8, - cpp_type=7, - label=1, - has_default_value=False, - default_value=False, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - ], - extensions=[], - nested_types=[], - enum_types=[], - serialized_options=None, - is_extendable=False, - syntax="proto3", - extension_ranges=[], - oneofs=[], - serialized_start=5617, - serialized_end=5676, -) - - -_TXRESULT = _descriptor.Descriptor( - name="TxResult", - full_name="tendermint.abci.TxResult", - filename=None, - file=DESCRIPTOR, - containing_type=None, - create_key=_descriptor._internal_create_key, - fields=[ - _descriptor.FieldDescriptor( - name="height", - full_name="tendermint.abci.TxResult.height", - index=0, - number=1, - type=3, - cpp_type=2, - label=1, - has_default_value=False, - default_value=0, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="index", - full_name="tendermint.abci.TxResult.index", - index=1, - number=2, - type=13, - cpp_type=3, - label=1, - has_default_value=False, - default_value=0, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="tx", - full_name="tendermint.abci.TxResult.tx", - index=2, - number=3, - type=12, - cpp_type=9, - label=1, - has_default_value=False, - default_value=b"", - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="result", - full_name="tendermint.abci.TxResult.result", - index=3, - number=4, - type=11, - cpp_type=10, - label=1, - has_default_value=False, - default_value=None, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=b"\310\336\037\000", - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - ], - extensions=[], - nested_types=[], - enum_types=[], - serialized_options=None, - is_extendable=False, - syntax="proto3", - extension_ranges=[], - oneofs=[], - serialized_start=5678, - serialized_end=5789, -) - - -_VALIDATOR = _descriptor.Descriptor( - name="Validator", - full_name="tendermint.abci.Validator", - filename=None, - file=DESCRIPTOR, - containing_type=None, - create_key=_descriptor._internal_create_key, - fields=[ - _descriptor.FieldDescriptor( - name="address", - full_name="tendermint.abci.Validator.address", - index=0, - number=1, - type=12, - cpp_type=9, - label=1, - has_default_value=False, - default_value=b"", - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="power", - full_name="tendermint.abci.Validator.power", - index=1, - number=3, - type=3, - cpp_type=2, - label=1, - has_default_value=False, - default_value=0, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - ], - extensions=[], - nested_types=[], - enum_types=[], - serialized_options=None, - is_extendable=False, - syntax="proto3", - extension_ranges=[], - oneofs=[], - serialized_start=5791, - serialized_end=5834, -) - - -_VALIDATORUPDATE = _descriptor.Descriptor( - name="ValidatorUpdate", - full_name="tendermint.abci.ValidatorUpdate", - filename=None, - file=DESCRIPTOR, - containing_type=None, - create_key=_descriptor._internal_create_key, - fields=[ - _descriptor.FieldDescriptor( - name="pub_key", - full_name="tendermint.abci.ValidatorUpdate.pub_key", - index=0, - number=1, - type=11, - cpp_type=10, - label=1, - has_default_value=False, - default_value=None, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=b"\310\336\037\000", - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="power", - full_name="tendermint.abci.ValidatorUpdate.power", - index=1, - number=2, - type=3, - cpp_type=2, - label=1, - has_default_value=False, - default_value=0, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - ], - extensions=[], - nested_types=[], - enum_types=[], - serialized_options=None, - is_extendable=False, - syntax="proto3", - extension_ranges=[], - oneofs=[], - serialized_start=5836, - serialized_end=5921, -) - - -_VOTEINFO = _descriptor.Descriptor( - name="VoteInfo", - full_name="tendermint.abci.VoteInfo", - filename=None, - file=DESCRIPTOR, - containing_type=None, - create_key=_descriptor._internal_create_key, - fields=[ - _descriptor.FieldDescriptor( - name="validator", - full_name="tendermint.abci.VoteInfo.validator", - index=0, - number=1, - type=11, - cpp_type=10, - label=1, - has_default_value=False, - default_value=None, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=b"\310\336\037\000", - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="signed_last_block", - full_name="tendermint.abci.VoteInfo.signed_last_block", - index=1, - number=2, - type=8, - cpp_type=7, - label=1, - has_default_value=False, - default_value=False, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - ], - extensions=[], - nested_types=[], - enum_types=[], - serialized_options=None, - is_extendable=False, - syntax="proto3", - extension_ranges=[], - oneofs=[], - serialized_start=5923, - serialized_end=6013, -) - - -_EVIDENCE = _descriptor.Descriptor( - name="Evidence", - full_name="tendermint.abci.Evidence", - filename=None, - file=DESCRIPTOR, - containing_type=None, - create_key=_descriptor._internal_create_key, - fields=[ - _descriptor.FieldDescriptor( - name="type", - full_name="tendermint.abci.Evidence.type", - index=0, - number=1, - type=14, - cpp_type=8, - label=1, - has_default_value=False, - default_value=0, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="validator", - full_name="tendermint.abci.Evidence.validator", - index=1, - number=2, - type=11, - cpp_type=10, - label=1, - has_default_value=False, - default_value=None, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=b"\310\336\037\000", - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="height", - full_name="tendermint.abci.Evidence.height", - index=2, - number=3, - type=3, - cpp_type=2, - label=1, - has_default_value=False, - default_value=0, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="time", - full_name="tendermint.abci.Evidence.time", - index=3, - number=4, - type=11, - cpp_type=10, - label=1, - has_default_value=False, - default_value=None, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=b"\310\336\037\000\220\337\037\001", - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="total_voting_power", - full_name="tendermint.abci.Evidence.total_voting_power", - index=4, - number=5, - type=3, - cpp_type=2, - label=1, - has_default_value=False, - default_value=0, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - ], - extensions=[], - nested_types=[], - enum_types=[], - serialized_options=None, - is_extendable=False, - syntax="proto3", - extension_ranges=[], - oneofs=[], - serialized_start=6016, - serialized_end=6220, -) - - -_SNAPSHOT = _descriptor.Descriptor( - name="Snapshot", - full_name="tendermint.abci.Snapshot", - filename=None, - file=DESCRIPTOR, - containing_type=None, - create_key=_descriptor._internal_create_key, - fields=[ - _descriptor.FieldDescriptor( - name="height", - full_name="tendermint.abci.Snapshot.height", - index=0, - number=1, - type=4, - cpp_type=4, - label=1, - has_default_value=False, - default_value=0, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="format", - full_name="tendermint.abci.Snapshot.format", - index=1, - number=2, - type=13, - cpp_type=3, - label=1, - has_default_value=False, - default_value=0, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="chunks", - full_name="tendermint.abci.Snapshot.chunks", - index=2, - number=3, - type=13, - cpp_type=3, - label=1, - has_default_value=False, - default_value=0, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="hash", - full_name="tendermint.abci.Snapshot.hash", - index=3, - number=4, - type=12, - cpp_type=9, - label=1, - has_default_value=False, - default_value=b"", - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="metadata", - full_name="tendermint.abci.Snapshot.metadata", - index=4, - number=5, - type=12, - cpp_type=9, - label=1, - has_default_value=False, - default_value=b"", - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - ], - extensions=[], - nested_types=[], - enum_types=[], - serialized_options=None, - is_extendable=False, - syntax="proto3", - extension_ranges=[], - oneofs=[], - serialized_start=6222, - serialized_end=6312, -) - -_REQUEST.fields_by_name["echo"].message_type = _REQUESTECHO -_REQUEST.fields_by_name["flush"].message_type = _REQUESTFLUSH -_REQUEST.fields_by_name["info"].message_type = _REQUESTINFO -_REQUEST.fields_by_name["set_option"].message_type = _REQUESTSETOPTION -_REQUEST.fields_by_name["init_chain"].message_type = _REQUESTINITCHAIN -_REQUEST.fields_by_name["query"].message_type = _REQUESTQUERY -_REQUEST.fields_by_name["begin_block"].message_type = _REQUESTBEGINBLOCK -_REQUEST.fields_by_name["check_tx"].message_type = _REQUESTCHECKTX -_REQUEST.fields_by_name["deliver_tx"].message_type = _REQUESTDELIVERTX -_REQUEST.fields_by_name["end_block"].message_type = _REQUESTENDBLOCK -_REQUEST.fields_by_name["commit"].message_type = _REQUESTCOMMIT -_REQUEST.fields_by_name["list_snapshots"].message_type = _REQUESTLISTSNAPSHOTS -_REQUEST.fields_by_name["offer_snapshot"].message_type = _REQUESTOFFERSNAPSHOT -_REQUEST.fields_by_name["load_snapshot_chunk"].message_type = _REQUESTLOADSNAPSHOTCHUNK -_REQUEST.fields_by_name[ - "apply_snapshot_chunk" -].message_type = _REQUESTAPPLYSNAPSHOTCHUNK -_REQUEST.oneofs_by_name["value"].fields.append(_REQUEST.fields_by_name["echo"]) -_REQUEST.fields_by_name["echo"].containing_oneof = _REQUEST.oneofs_by_name["value"] -_REQUEST.oneofs_by_name["value"].fields.append(_REQUEST.fields_by_name["flush"]) -_REQUEST.fields_by_name["flush"].containing_oneof = _REQUEST.oneofs_by_name["value"] -_REQUEST.oneofs_by_name["value"].fields.append(_REQUEST.fields_by_name["info"]) -_REQUEST.fields_by_name["info"].containing_oneof = _REQUEST.oneofs_by_name["value"] -_REQUEST.oneofs_by_name["value"].fields.append(_REQUEST.fields_by_name["set_option"]) -_REQUEST.fields_by_name["set_option"].containing_oneof = _REQUEST.oneofs_by_name[ - "value" -] -_REQUEST.oneofs_by_name["value"].fields.append(_REQUEST.fields_by_name["init_chain"]) -_REQUEST.fields_by_name["init_chain"].containing_oneof = _REQUEST.oneofs_by_name[ - "value" -] -_REQUEST.oneofs_by_name["value"].fields.append(_REQUEST.fields_by_name["query"]) -_REQUEST.fields_by_name["query"].containing_oneof = _REQUEST.oneofs_by_name["value"] -_REQUEST.oneofs_by_name["value"].fields.append(_REQUEST.fields_by_name["begin_block"]) -_REQUEST.fields_by_name["begin_block"].containing_oneof = _REQUEST.oneofs_by_name[ - "value" -] -_REQUEST.oneofs_by_name["value"].fields.append(_REQUEST.fields_by_name["check_tx"]) -_REQUEST.fields_by_name["check_tx"].containing_oneof = _REQUEST.oneofs_by_name["value"] -_REQUEST.oneofs_by_name["value"].fields.append(_REQUEST.fields_by_name["deliver_tx"]) -_REQUEST.fields_by_name["deliver_tx"].containing_oneof = _REQUEST.oneofs_by_name[ - "value" -] -_REQUEST.oneofs_by_name["value"].fields.append(_REQUEST.fields_by_name["end_block"]) -_REQUEST.fields_by_name["end_block"].containing_oneof = _REQUEST.oneofs_by_name["value"] -_REQUEST.oneofs_by_name["value"].fields.append(_REQUEST.fields_by_name["commit"]) -_REQUEST.fields_by_name["commit"].containing_oneof = _REQUEST.oneofs_by_name["value"] -_REQUEST.oneofs_by_name["value"].fields.append( - _REQUEST.fields_by_name["list_snapshots"] -) -_REQUEST.fields_by_name["list_snapshots"].containing_oneof = _REQUEST.oneofs_by_name[ - "value" -] -_REQUEST.oneofs_by_name["value"].fields.append( - _REQUEST.fields_by_name["offer_snapshot"] -) -_REQUEST.fields_by_name["offer_snapshot"].containing_oneof = _REQUEST.oneofs_by_name[ - "value" -] -_REQUEST.oneofs_by_name["value"].fields.append( - _REQUEST.fields_by_name["load_snapshot_chunk"] -) -_REQUEST.fields_by_name[ - "load_snapshot_chunk" -].containing_oneof = _REQUEST.oneofs_by_name["value"] -_REQUEST.oneofs_by_name["value"].fields.append( - _REQUEST.fields_by_name["apply_snapshot_chunk"] -) -_REQUEST.fields_by_name[ - "apply_snapshot_chunk" -].containing_oneof = _REQUEST.oneofs_by_name["value"] -_REQUESTINITCHAIN.fields_by_name[ - "time" -].message_type = google_dot_protobuf_dot_timestamp__pb2._TIMESTAMP -_REQUESTINITCHAIN.fields_by_name["consensus_params"].message_type = _CONSENSUSPARAMS -_REQUESTINITCHAIN.fields_by_name["validators"].message_type = _VALIDATORUPDATE -_REQUESTBEGINBLOCK.fields_by_name[ - "header" -].message_type = tendermint_dot_types_dot_types__pb2._HEADER -_REQUESTBEGINBLOCK.fields_by_name["last_commit_info"].message_type = _LASTCOMMITINFO -_REQUESTBEGINBLOCK.fields_by_name["byzantine_validators"].message_type = _EVIDENCE -_REQUESTCHECKTX.fields_by_name["type"].enum_type = _CHECKTXTYPE -_REQUESTOFFERSNAPSHOT.fields_by_name["snapshot"].message_type = _SNAPSHOT -_RESPONSE.fields_by_name["exception"].message_type = _RESPONSEEXCEPTION -_RESPONSE.fields_by_name["echo"].message_type = _RESPONSEECHO -_RESPONSE.fields_by_name["flush"].message_type = _RESPONSEFLUSH -_RESPONSE.fields_by_name["info"].message_type = _RESPONSEINFO -_RESPONSE.fields_by_name["set_option"].message_type = _RESPONSESETOPTION -_RESPONSE.fields_by_name["init_chain"].message_type = _RESPONSEINITCHAIN -_RESPONSE.fields_by_name["query"].message_type = _RESPONSEQUERY -_RESPONSE.fields_by_name["begin_block"].message_type = _RESPONSEBEGINBLOCK -_RESPONSE.fields_by_name["check_tx"].message_type = _RESPONSECHECKTX -_RESPONSE.fields_by_name["deliver_tx"].message_type = _RESPONSEDELIVERTX -_RESPONSE.fields_by_name["end_block"].message_type = _RESPONSEENDBLOCK -_RESPONSE.fields_by_name["commit"].message_type = _RESPONSECOMMIT -_RESPONSE.fields_by_name["list_snapshots"].message_type = _RESPONSELISTSNAPSHOTS -_RESPONSE.fields_by_name["offer_snapshot"].message_type = _RESPONSEOFFERSNAPSHOT -_RESPONSE.fields_by_name[ - "load_snapshot_chunk" -].message_type = _RESPONSELOADSNAPSHOTCHUNK -_RESPONSE.fields_by_name[ - "apply_snapshot_chunk" -].message_type = _RESPONSEAPPLYSNAPSHOTCHUNK -_RESPONSE.oneofs_by_name["value"].fields.append(_RESPONSE.fields_by_name["exception"]) -_RESPONSE.fields_by_name["exception"].containing_oneof = _RESPONSE.oneofs_by_name[ - "value" -] -_RESPONSE.oneofs_by_name["value"].fields.append(_RESPONSE.fields_by_name["echo"]) -_RESPONSE.fields_by_name["echo"].containing_oneof = _RESPONSE.oneofs_by_name["value"] -_RESPONSE.oneofs_by_name["value"].fields.append(_RESPONSE.fields_by_name["flush"]) -_RESPONSE.fields_by_name["flush"].containing_oneof = _RESPONSE.oneofs_by_name["value"] -_RESPONSE.oneofs_by_name["value"].fields.append(_RESPONSE.fields_by_name["info"]) -_RESPONSE.fields_by_name["info"].containing_oneof = _RESPONSE.oneofs_by_name["value"] -_RESPONSE.oneofs_by_name["value"].fields.append(_RESPONSE.fields_by_name["set_option"]) -_RESPONSE.fields_by_name["set_option"].containing_oneof = _RESPONSE.oneofs_by_name[ - "value" -] -_RESPONSE.oneofs_by_name["value"].fields.append(_RESPONSE.fields_by_name["init_chain"]) -_RESPONSE.fields_by_name["init_chain"].containing_oneof = _RESPONSE.oneofs_by_name[ - "value" -] -_RESPONSE.oneofs_by_name["value"].fields.append(_RESPONSE.fields_by_name["query"]) -_RESPONSE.fields_by_name["query"].containing_oneof = _RESPONSE.oneofs_by_name["value"] -_RESPONSE.oneofs_by_name["value"].fields.append(_RESPONSE.fields_by_name["begin_block"]) -_RESPONSE.fields_by_name["begin_block"].containing_oneof = _RESPONSE.oneofs_by_name[ - "value" -] -_RESPONSE.oneofs_by_name["value"].fields.append(_RESPONSE.fields_by_name["check_tx"]) -_RESPONSE.fields_by_name["check_tx"].containing_oneof = _RESPONSE.oneofs_by_name[ - "value" -] -_RESPONSE.oneofs_by_name["value"].fields.append(_RESPONSE.fields_by_name["deliver_tx"]) -_RESPONSE.fields_by_name["deliver_tx"].containing_oneof = _RESPONSE.oneofs_by_name[ - "value" -] -_RESPONSE.oneofs_by_name["value"].fields.append(_RESPONSE.fields_by_name["end_block"]) -_RESPONSE.fields_by_name["end_block"].containing_oneof = _RESPONSE.oneofs_by_name[ - "value" -] -_RESPONSE.oneofs_by_name["value"].fields.append(_RESPONSE.fields_by_name["commit"]) -_RESPONSE.fields_by_name["commit"].containing_oneof = _RESPONSE.oneofs_by_name["value"] -_RESPONSE.oneofs_by_name["value"].fields.append( - _RESPONSE.fields_by_name["list_snapshots"] -) -_RESPONSE.fields_by_name["list_snapshots"].containing_oneof = _RESPONSE.oneofs_by_name[ - "value" -] -_RESPONSE.oneofs_by_name["value"].fields.append( - _RESPONSE.fields_by_name["offer_snapshot"] -) -_RESPONSE.fields_by_name["offer_snapshot"].containing_oneof = _RESPONSE.oneofs_by_name[ - "value" -] -_RESPONSE.oneofs_by_name["value"].fields.append( - _RESPONSE.fields_by_name["load_snapshot_chunk"] -) -_RESPONSE.fields_by_name[ - "load_snapshot_chunk" -].containing_oneof = _RESPONSE.oneofs_by_name["value"] -_RESPONSE.oneofs_by_name["value"].fields.append( - _RESPONSE.fields_by_name["apply_snapshot_chunk"] -) -_RESPONSE.fields_by_name[ - "apply_snapshot_chunk" -].containing_oneof = _RESPONSE.oneofs_by_name["value"] -_RESPONSEINITCHAIN.fields_by_name["consensus_params"].message_type = _CONSENSUSPARAMS -_RESPONSEINITCHAIN.fields_by_name["validators"].message_type = _VALIDATORUPDATE -_RESPONSEQUERY.fields_by_name[ - "proof_ops" -].message_type = tendermint_dot_crypto_dot_proof__pb2._PROOFOPS -_RESPONSEBEGINBLOCK.fields_by_name["events"].message_type = _EVENT -_RESPONSECHECKTX.fields_by_name["events"].message_type = _EVENT -_RESPONSEDELIVERTX.fields_by_name["events"].message_type = _EVENT -_RESPONSEENDBLOCK.fields_by_name["validator_updates"].message_type = _VALIDATORUPDATE -_RESPONSEENDBLOCK.fields_by_name[ - "consensus_param_updates" -].message_type = _CONSENSUSPARAMS -_RESPONSEENDBLOCK.fields_by_name["events"].message_type = _EVENT -_RESPONSELISTSNAPSHOTS.fields_by_name["snapshots"].message_type = _SNAPSHOT -_RESPONSEOFFERSNAPSHOT.fields_by_name[ - "result" -].enum_type = _RESPONSEOFFERSNAPSHOT_RESULT -_RESPONSEOFFERSNAPSHOT_RESULT.containing_type = _RESPONSEOFFERSNAPSHOT -_RESPONSEAPPLYSNAPSHOTCHUNK.fields_by_name[ - "result" -].enum_type = _RESPONSEAPPLYSNAPSHOTCHUNK_RESULT -_RESPONSEAPPLYSNAPSHOTCHUNK_RESULT.containing_type = _RESPONSEAPPLYSNAPSHOTCHUNK -_CONSENSUSPARAMS.fields_by_name["block"].message_type = _BLOCKPARAMS -_CONSENSUSPARAMS.fields_by_name[ - "evidence" -].message_type = tendermint_dot_types_dot_params__pb2._EVIDENCEPARAMS -_CONSENSUSPARAMS.fields_by_name[ - "validator" -].message_type = tendermint_dot_types_dot_params__pb2._VALIDATORPARAMS -_CONSENSUSPARAMS.fields_by_name[ - "version" -].message_type = tendermint_dot_types_dot_params__pb2._VERSIONPARAMS -_LASTCOMMITINFO.fields_by_name["votes"].message_type = _VOTEINFO -_EVENT.fields_by_name["attributes"].message_type = _EVENTATTRIBUTE -_TXRESULT.fields_by_name["result"].message_type = _RESPONSEDELIVERTX -_VALIDATORUPDATE.fields_by_name[ - "pub_key" -].message_type = tendermint_dot_crypto_dot_keys__pb2._PUBLICKEY -_VOTEINFO.fields_by_name["validator"].message_type = _VALIDATOR -_EVIDENCE.fields_by_name["type"].enum_type = _EVIDENCETYPE -_EVIDENCE.fields_by_name["validator"].message_type = _VALIDATOR -_EVIDENCE.fields_by_name[ - "time" -].message_type = google_dot_protobuf_dot_timestamp__pb2._TIMESTAMP -DESCRIPTOR.message_types_by_name["Request"] = _REQUEST -DESCRIPTOR.message_types_by_name["RequestEcho"] = _REQUESTECHO -DESCRIPTOR.message_types_by_name["RequestFlush"] = _REQUESTFLUSH -DESCRIPTOR.message_types_by_name["RequestInfo"] = _REQUESTINFO -DESCRIPTOR.message_types_by_name["RequestSetOption"] = _REQUESTSETOPTION -DESCRIPTOR.message_types_by_name["RequestInitChain"] = _REQUESTINITCHAIN -DESCRIPTOR.message_types_by_name["RequestQuery"] = _REQUESTQUERY -DESCRIPTOR.message_types_by_name["RequestBeginBlock"] = _REQUESTBEGINBLOCK -DESCRIPTOR.message_types_by_name["RequestCheckTx"] = _REQUESTCHECKTX -DESCRIPTOR.message_types_by_name["RequestDeliverTx"] = _REQUESTDELIVERTX -DESCRIPTOR.message_types_by_name["RequestEndBlock"] = _REQUESTENDBLOCK -DESCRIPTOR.message_types_by_name["RequestCommit"] = _REQUESTCOMMIT -DESCRIPTOR.message_types_by_name["RequestListSnapshots"] = _REQUESTLISTSNAPSHOTS -DESCRIPTOR.message_types_by_name["RequestOfferSnapshot"] = _REQUESTOFFERSNAPSHOT -DESCRIPTOR.message_types_by_name["RequestLoadSnapshotChunk"] = _REQUESTLOADSNAPSHOTCHUNK -DESCRIPTOR.message_types_by_name[ - "RequestApplySnapshotChunk" -] = _REQUESTAPPLYSNAPSHOTCHUNK -DESCRIPTOR.message_types_by_name["Response"] = _RESPONSE -DESCRIPTOR.message_types_by_name["ResponseException"] = _RESPONSEEXCEPTION -DESCRIPTOR.message_types_by_name["ResponseEcho"] = _RESPONSEECHO -DESCRIPTOR.message_types_by_name["ResponseFlush"] = _RESPONSEFLUSH -DESCRIPTOR.message_types_by_name["ResponseInfo"] = _RESPONSEINFO -DESCRIPTOR.message_types_by_name["ResponseSetOption"] = _RESPONSESETOPTION -DESCRIPTOR.message_types_by_name["ResponseInitChain"] = _RESPONSEINITCHAIN -DESCRIPTOR.message_types_by_name["ResponseQuery"] = _RESPONSEQUERY -DESCRIPTOR.message_types_by_name["ResponseBeginBlock"] = _RESPONSEBEGINBLOCK -DESCRIPTOR.message_types_by_name["ResponseCheckTx"] = _RESPONSECHECKTX -DESCRIPTOR.message_types_by_name["ResponseDeliverTx"] = _RESPONSEDELIVERTX -DESCRIPTOR.message_types_by_name["ResponseEndBlock"] = _RESPONSEENDBLOCK -DESCRIPTOR.message_types_by_name["ResponseCommit"] = _RESPONSECOMMIT -DESCRIPTOR.message_types_by_name["ResponseListSnapshots"] = _RESPONSELISTSNAPSHOTS -DESCRIPTOR.message_types_by_name["ResponseOfferSnapshot"] = _RESPONSEOFFERSNAPSHOT -DESCRIPTOR.message_types_by_name[ - "ResponseLoadSnapshotChunk" -] = _RESPONSELOADSNAPSHOTCHUNK -DESCRIPTOR.message_types_by_name[ - "ResponseApplySnapshotChunk" -] = _RESPONSEAPPLYSNAPSHOTCHUNK -DESCRIPTOR.message_types_by_name["ConsensusParams"] = _CONSENSUSPARAMS -DESCRIPTOR.message_types_by_name["BlockParams"] = _BLOCKPARAMS -DESCRIPTOR.message_types_by_name["LastCommitInfo"] = _LASTCOMMITINFO -DESCRIPTOR.message_types_by_name["Event"] = _EVENT -DESCRIPTOR.message_types_by_name["EventAttribute"] = _EVENTATTRIBUTE -DESCRIPTOR.message_types_by_name["TxResult"] = _TXRESULT -DESCRIPTOR.message_types_by_name["Validator"] = _VALIDATOR -DESCRIPTOR.message_types_by_name["ValidatorUpdate"] = _VALIDATORUPDATE -DESCRIPTOR.message_types_by_name["VoteInfo"] = _VOTEINFO -DESCRIPTOR.message_types_by_name["Evidence"] = _EVIDENCE -DESCRIPTOR.message_types_by_name["Snapshot"] = _SNAPSHOT -DESCRIPTOR.enum_types_by_name["CheckTxType"] = _CHECKTXTYPE -DESCRIPTOR.enum_types_by_name["EvidenceType"] = _EVIDENCETYPE -_sym_db.RegisterFileDescriptor(DESCRIPTOR) - -Request = _reflection.GeneratedProtocolMessageType( - "Request", - (_message.Message,), - { - "DESCRIPTOR": _REQUEST, - "__module__": "tendermint.abci.types_pb2" - # @@protoc_insertion_point(class_scope:tendermint.abci.Request) - }, -) -_sym_db.RegisterMessage(Request) - -RequestEcho = _reflection.GeneratedProtocolMessageType( - "RequestEcho", - (_message.Message,), - { - "DESCRIPTOR": _REQUESTECHO, - "__module__": "tendermint.abci.types_pb2" - # @@protoc_insertion_point(class_scope:tendermint.abci.RequestEcho) - }, -) -_sym_db.RegisterMessage(RequestEcho) - -RequestFlush = _reflection.GeneratedProtocolMessageType( - "RequestFlush", - (_message.Message,), - { - "DESCRIPTOR": _REQUESTFLUSH, - "__module__": "tendermint.abci.types_pb2" - # @@protoc_insertion_point(class_scope:tendermint.abci.RequestFlush) - }, -) -_sym_db.RegisterMessage(RequestFlush) - -RequestInfo = _reflection.GeneratedProtocolMessageType( - "RequestInfo", - (_message.Message,), - { - "DESCRIPTOR": _REQUESTINFO, - "__module__": "tendermint.abci.types_pb2" - # @@protoc_insertion_point(class_scope:tendermint.abci.RequestInfo) - }, -) -_sym_db.RegisterMessage(RequestInfo) - -RequestSetOption = _reflection.GeneratedProtocolMessageType( - "RequestSetOption", - (_message.Message,), - { - "DESCRIPTOR": _REQUESTSETOPTION, - "__module__": "tendermint.abci.types_pb2" - # @@protoc_insertion_point(class_scope:tendermint.abci.RequestSetOption) - }, -) -_sym_db.RegisterMessage(RequestSetOption) - -RequestInitChain = _reflection.GeneratedProtocolMessageType( - "RequestInitChain", - (_message.Message,), - { - "DESCRIPTOR": _REQUESTINITCHAIN, - "__module__": "tendermint.abci.types_pb2" - # @@protoc_insertion_point(class_scope:tendermint.abci.RequestInitChain) - }, -) -_sym_db.RegisterMessage(RequestInitChain) - -RequestQuery = _reflection.GeneratedProtocolMessageType( - "RequestQuery", - (_message.Message,), - { - "DESCRIPTOR": _REQUESTQUERY, - "__module__": "tendermint.abci.types_pb2" - # @@protoc_insertion_point(class_scope:tendermint.abci.RequestQuery) - }, -) -_sym_db.RegisterMessage(RequestQuery) - -RequestBeginBlock = _reflection.GeneratedProtocolMessageType( - "RequestBeginBlock", - (_message.Message,), - { - "DESCRIPTOR": _REQUESTBEGINBLOCK, - "__module__": "tendermint.abci.types_pb2" - # @@protoc_insertion_point(class_scope:tendermint.abci.RequestBeginBlock) - }, -) -_sym_db.RegisterMessage(RequestBeginBlock) - -RequestCheckTx = _reflection.GeneratedProtocolMessageType( - "RequestCheckTx", - (_message.Message,), - { - "DESCRIPTOR": _REQUESTCHECKTX, - "__module__": "tendermint.abci.types_pb2" - # @@protoc_insertion_point(class_scope:tendermint.abci.RequestCheckTx) - }, -) -_sym_db.RegisterMessage(RequestCheckTx) - -RequestDeliverTx = _reflection.GeneratedProtocolMessageType( - "RequestDeliverTx", - (_message.Message,), - { - "DESCRIPTOR": _REQUESTDELIVERTX, - "__module__": "tendermint.abci.types_pb2" - # @@protoc_insertion_point(class_scope:tendermint.abci.RequestDeliverTx) - }, -) -_sym_db.RegisterMessage(RequestDeliverTx) - -RequestEndBlock = _reflection.GeneratedProtocolMessageType( - "RequestEndBlock", - (_message.Message,), - { - "DESCRIPTOR": _REQUESTENDBLOCK, - "__module__": "tendermint.abci.types_pb2" - # @@protoc_insertion_point(class_scope:tendermint.abci.RequestEndBlock) - }, -) -_sym_db.RegisterMessage(RequestEndBlock) - -RequestCommit = _reflection.GeneratedProtocolMessageType( - "RequestCommit", - (_message.Message,), - { - "DESCRIPTOR": _REQUESTCOMMIT, - "__module__": "tendermint.abci.types_pb2" - # @@protoc_insertion_point(class_scope:tendermint.abci.RequestCommit) - }, -) -_sym_db.RegisterMessage(RequestCommit) - -RequestListSnapshots = _reflection.GeneratedProtocolMessageType( - "RequestListSnapshots", - (_message.Message,), - { - "DESCRIPTOR": _REQUESTLISTSNAPSHOTS, - "__module__": "tendermint.abci.types_pb2" - # @@protoc_insertion_point(class_scope:tendermint.abci.RequestListSnapshots) - }, -) -_sym_db.RegisterMessage(RequestListSnapshots) - -RequestOfferSnapshot = _reflection.GeneratedProtocolMessageType( - "RequestOfferSnapshot", - (_message.Message,), - { - "DESCRIPTOR": _REQUESTOFFERSNAPSHOT, - "__module__": "tendermint.abci.types_pb2" - # @@protoc_insertion_point(class_scope:tendermint.abci.RequestOfferSnapshot) - }, -) -_sym_db.RegisterMessage(RequestOfferSnapshot) - -RequestLoadSnapshotChunk = _reflection.GeneratedProtocolMessageType( - "RequestLoadSnapshotChunk", - (_message.Message,), - { - "DESCRIPTOR": _REQUESTLOADSNAPSHOTCHUNK, - "__module__": "tendermint.abci.types_pb2" - # @@protoc_insertion_point(class_scope:tendermint.abci.RequestLoadSnapshotChunk) - }, -) -_sym_db.RegisterMessage(RequestLoadSnapshotChunk) - -RequestApplySnapshotChunk = _reflection.GeneratedProtocolMessageType( - "RequestApplySnapshotChunk", - (_message.Message,), - { - "DESCRIPTOR": _REQUESTAPPLYSNAPSHOTCHUNK, - "__module__": "tendermint.abci.types_pb2" - # @@protoc_insertion_point(class_scope:tendermint.abci.RequestApplySnapshotChunk) - }, -) -_sym_db.RegisterMessage(RequestApplySnapshotChunk) - -Response = _reflection.GeneratedProtocolMessageType( - "Response", - (_message.Message,), - { - "DESCRIPTOR": _RESPONSE, - "__module__": "tendermint.abci.types_pb2" - # @@protoc_insertion_point(class_scope:tendermint.abci.Response) - }, -) -_sym_db.RegisterMessage(Response) - -ResponseException = _reflection.GeneratedProtocolMessageType( - "ResponseException", - (_message.Message,), - { - "DESCRIPTOR": _RESPONSEEXCEPTION, - "__module__": "tendermint.abci.types_pb2" - # @@protoc_insertion_point(class_scope:tendermint.abci.ResponseException) - }, -) -_sym_db.RegisterMessage(ResponseException) - -ResponseEcho = _reflection.GeneratedProtocolMessageType( - "ResponseEcho", - (_message.Message,), - { - "DESCRIPTOR": _RESPONSEECHO, - "__module__": "tendermint.abci.types_pb2" - # @@protoc_insertion_point(class_scope:tendermint.abci.ResponseEcho) - }, -) -_sym_db.RegisterMessage(ResponseEcho) - -ResponseFlush = _reflection.GeneratedProtocolMessageType( - "ResponseFlush", - (_message.Message,), - { - "DESCRIPTOR": _RESPONSEFLUSH, - "__module__": "tendermint.abci.types_pb2" - # @@protoc_insertion_point(class_scope:tendermint.abci.ResponseFlush) - }, -) -_sym_db.RegisterMessage(ResponseFlush) - -ResponseInfo = _reflection.GeneratedProtocolMessageType( - "ResponseInfo", - (_message.Message,), - { - "DESCRIPTOR": _RESPONSEINFO, - "__module__": "tendermint.abci.types_pb2" - # @@protoc_insertion_point(class_scope:tendermint.abci.ResponseInfo) - }, -) -_sym_db.RegisterMessage(ResponseInfo) - -ResponseSetOption = _reflection.GeneratedProtocolMessageType( - "ResponseSetOption", - (_message.Message,), - { - "DESCRIPTOR": _RESPONSESETOPTION, - "__module__": "tendermint.abci.types_pb2" - # @@protoc_insertion_point(class_scope:tendermint.abci.ResponseSetOption) - }, -) -_sym_db.RegisterMessage(ResponseSetOption) - -ResponseInitChain = _reflection.GeneratedProtocolMessageType( - "ResponseInitChain", - (_message.Message,), - { - "DESCRIPTOR": _RESPONSEINITCHAIN, - "__module__": "tendermint.abci.types_pb2" - # @@protoc_insertion_point(class_scope:tendermint.abci.ResponseInitChain) - }, -) -_sym_db.RegisterMessage(ResponseInitChain) - -ResponseQuery = _reflection.GeneratedProtocolMessageType( - "ResponseQuery", - (_message.Message,), - { - "DESCRIPTOR": _RESPONSEQUERY, - "__module__": "tendermint.abci.types_pb2" - # @@protoc_insertion_point(class_scope:tendermint.abci.ResponseQuery) - }, -) -_sym_db.RegisterMessage(ResponseQuery) - -ResponseBeginBlock = _reflection.GeneratedProtocolMessageType( - "ResponseBeginBlock", - (_message.Message,), - { - "DESCRIPTOR": _RESPONSEBEGINBLOCK, - "__module__": "tendermint.abci.types_pb2" - # @@protoc_insertion_point(class_scope:tendermint.abci.ResponseBeginBlock) - }, -) -_sym_db.RegisterMessage(ResponseBeginBlock) - -ResponseCheckTx = _reflection.GeneratedProtocolMessageType( - "ResponseCheckTx", - (_message.Message,), - { - "DESCRIPTOR": _RESPONSECHECKTX, - "__module__": "tendermint.abci.types_pb2" - # @@protoc_insertion_point(class_scope:tendermint.abci.ResponseCheckTx) - }, -) -_sym_db.RegisterMessage(ResponseCheckTx) - -ResponseDeliverTx = _reflection.GeneratedProtocolMessageType( - "ResponseDeliverTx", - (_message.Message,), - { - "DESCRIPTOR": _RESPONSEDELIVERTX, - "__module__": "tendermint.abci.types_pb2" - # @@protoc_insertion_point(class_scope:tendermint.abci.ResponseDeliverTx) - }, -) -_sym_db.RegisterMessage(ResponseDeliverTx) - -ResponseEndBlock = _reflection.GeneratedProtocolMessageType( - "ResponseEndBlock", - (_message.Message,), - { - "DESCRIPTOR": _RESPONSEENDBLOCK, - "__module__": "tendermint.abci.types_pb2" - # @@protoc_insertion_point(class_scope:tendermint.abci.ResponseEndBlock) - }, -) -_sym_db.RegisterMessage(ResponseEndBlock) - -ResponseCommit = _reflection.GeneratedProtocolMessageType( - "ResponseCommit", - (_message.Message,), - { - "DESCRIPTOR": _RESPONSECOMMIT, - "__module__": "tendermint.abci.types_pb2" - # @@protoc_insertion_point(class_scope:tendermint.abci.ResponseCommit) - }, -) -_sym_db.RegisterMessage(ResponseCommit) - -ResponseListSnapshots = _reflection.GeneratedProtocolMessageType( - "ResponseListSnapshots", - (_message.Message,), - { - "DESCRIPTOR": _RESPONSELISTSNAPSHOTS, - "__module__": "tendermint.abci.types_pb2" - # @@protoc_insertion_point(class_scope:tendermint.abci.ResponseListSnapshots) - }, -) -_sym_db.RegisterMessage(ResponseListSnapshots) - -ResponseOfferSnapshot = _reflection.GeneratedProtocolMessageType( - "ResponseOfferSnapshot", - (_message.Message,), - { - "DESCRIPTOR": _RESPONSEOFFERSNAPSHOT, - "__module__": "tendermint.abci.types_pb2" - # @@protoc_insertion_point(class_scope:tendermint.abci.ResponseOfferSnapshot) - }, -) -_sym_db.RegisterMessage(ResponseOfferSnapshot) - -ResponseLoadSnapshotChunk = _reflection.GeneratedProtocolMessageType( - "ResponseLoadSnapshotChunk", - (_message.Message,), - { - "DESCRIPTOR": _RESPONSELOADSNAPSHOTCHUNK, - "__module__": "tendermint.abci.types_pb2" - # @@protoc_insertion_point(class_scope:tendermint.abci.ResponseLoadSnapshotChunk) - }, -) -_sym_db.RegisterMessage(ResponseLoadSnapshotChunk) - -ResponseApplySnapshotChunk = _reflection.GeneratedProtocolMessageType( - "ResponseApplySnapshotChunk", - (_message.Message,), - { - "DESCRIPTOR": _RESPONSEAPPLYSNAPSHOTCHUNK, - "__module__": "tendermint.abci.types_pb2" - # @@protoc_insertion_point(class_scope:tendermint.abci.ResponseApplySnapshotChunk) - }, -) -_sym_db.RegisterMessage(ResponseApplySnapshotChunk) - -ConsensusParams = _reflection.GeneratedProtocolMessageType( - "ConsensusParams", - (_message.Message,), - { - "DESCRIPTOR": _CONSENSUSPARAMS, - "__module__": "tendermint.abci.types_pb2" - # @@protoc_insertion_point(class_scope:tendermint.abci.ConsensusParams) - }, -) -_sym_db.RegisterMessage(ConsensusParams) - -BlockParams = _reflection.GeneratedProtocolMessageType( - "BlockParams", - (_message.Message,), - { - "DESCRIPTOR": _BLOCKPARAMS, - "__module__": "tendermint.abci.types_pb2" - # @@protoc_insertion_point(class_scope:tendermint.abci.BlockParams) - }, -) -_sym_db.RegisterMessage(BlockParams) - -LastCommitInfo = _reflection.GeneratedProtocolMessageType( - "LastCommitInfo", - (_message.Message,), - { - "DESCRIPTOR": _LASTCOMMITINFO, - "__module__": "tendermint.abci.types_pb2" - # @@protoc_insertion_point(class_scope:tendermint.abci.LastCommitInfo) - }, -) -_sym_db.RegisterMessage(LastCommitInfo) - -Event = _reflection.GeneratedProtocolMessageType( - "Event", - (_message.Message,), - { - "DESCRIPTOR": _EVENT, - "__module__": "tendermint.abci.types_pb2" - # @@protoc_insertion_point(class_scope:tendermint.abci.Event) - }, -) -_sym_db.RegisterMessage(Event) - -EventAttribute = _reflection.GeneratedProtocolMessageType( - "EventAttribute", - (_message.Message,), - { - "DESCRIPTOR": _EVENTATTRIBUTE, - "__module__": "tendermint.abci.types_pb2" - # @@protoc_insertion_point(class_scope:tendermint.abci.EventAttribute) - }, -) -_sym_db.RegisterMessage(EventAttribute) - -TxResult = _reflection.GeneratedProtocolMessageType( - "TxResult", - (_message.Message,), - { - "DESCRIPTOR": _TXRESULT, - "__module__": "tendermint.abci.types_pb2" - # @@protoc_insertion_point(class_scope:tendermint.abci.TxResult) - }, -) -_sym_db.RegisterMessage(TxResult) - -Validator = _reflection.GeneratedProtocolMessageType( - "Validator", - (_message.Message,), - { - "DESCRIPTOR": _VALIDATOR, - "__module__": "tendermint.abci.types_pb2" - # @@protoc_insertion_point(class_scope:tendermint.abci.Validator) - }, -) -_sym_db.RegisterMessage(Validator) - -ValidatorUpdate = _reflection.GeneratedProtocolMessageType( - "ValidatorUpdate", - (_message.Message,), - { - "DESCRIPTOR": _VALIDATORUPDATE, - "__module__": "tendermint.abci.types_pb2" - # @@protoc_insertion_point(class_scope:tendermint.abci.ValidatorUpdate) - }, -) -_sym_db.RegisterMessage(ValidatorUpdate) - -VoteInfo = _reflection.GeneratedProtocolMessageType( - "VoteInfo", - (_message.Message,), - { - "DESCRIPTOR": _VOTEINFO, - "__module__": "tendermint.abci.types_pb2" - # @@protoc_insertion_point(class_scope:tendermint.abci.VoteInfo) - }, -) -_sym_db.RegisterMessage(VoteInfo) - -Evidence = _reflection.GeneratedProtocolMessageType( - "Evidence", - (_message.Message,), - { - "DESCRIPTOR": _EVIDENCE, - "__module__": "tendermint.abci.types_pb2" - # @@protoc_insertion_point(class_scope:tendermint.abci.Evidence) - }, -) -_sym_db.RegisterMessage(Evidence) - -Snapshot = _reflection.GeneratedProtocolMessageType( - "Snapshot", - (_message.Message,), - { - "DESCRIPTOR": _SNAPSHOT, - "__module__": "tendermint.abci.types_pb2" - # @@protoc_insertion_point(class_scope:tendermint.abci.Snapshot) - }, -) -_sym_db.RegisterMessage(Snapshot) - - -DESCRIPTOR._options = None -_CHECKTXTYPE.values_by_name["NEW"]._options = None -_CHECKTXTYPE.values_by_name["RECHECK"]._options = None -_REQUESTINITCHAIN.fields_by_name["time"]._options = None -_REQUESTINITCHAIN.fields_by_name["validators"]._options = None -_REQUESTBEGINBLOCK.fields_by_name["header"]._options = None -_REQUESTBEGINBLOCK.fields_by_name["last_commit_info"]._options = None -_REQUESTBEGINBLOCK.fields_by_name["byzantine_validators"]._options = None -_RESPONSEINITCHAIN.fields_by_name["validators"]._options = None -_RESPONSEBEGINBLOCK.fields_by_name["events"]._options = None -_RESPONSECHECKTX.fields_by_name["events"]._options = None -_RESPONSEDELIVERTX.fields_by_name["events"]._options = None -_RESPONSEENDBLOCK.fields_by_name["validator_updates"]._options = None -_RESPONSEENDBLOCK.fields_by_name["events"]._options = None -_LASTCOMMITINFO.fields_by_name["votes"]._options = None -_EVENT.fields_by_name["attributes"]._options = None -_TXRESULT.fields_by_name["result"]._options = None -_VALIDATORUPDATE.fields_by_name["pub_key"]._options = None -_VOTEINFO.fields_by_name["validator"]._options = None -_EVIDENCE.fields_by_name["validator"]._options = None -_EVIDENCE.fields_by_name["time"]._options = None - -_ABCIAPPLICATION = _descriptor.ServiceDescriptor( - name="ABCIApplication", - full_name="tendermint.abci.ABCIApplication", - file=DESCRIPTOR, - index=0, - serialized_options=None, - create_key=_descriptor._internal_create_key, - serialized_start=6448, - serialized_end=7731, - methods=[ - _descriptor.MethodDescriptor( - name="Echo", - full_name="tendermint.abci.ABCIApplication.Echo", - index=0, - containing_service=None, - input_type=_REQUESTECHO, - output_type=_RESPONSEECHO, - serialized_options=None, - create_key=_descriptor._internal_create_key, - ), - _descriptor.MethodDescriptor( - name="Flush", - full_name="tendermint.abci.ABCIApplication.Flush", - index=1, - containing_service=None, - input_type=_REQUESTFLUSH, - output_type=_RESPONSEFLUSH, - serialized_options=None, - create_key=_descriptor._internal_create_key, - ), - _descriptor.MethodDescriptor( - name="Info", - full_name="tendermint.abci.ABCIApplication.Info", - index=2, - containing_service=None, - input_type=_REQUESTINFO, - output_type=_RESPONSEINFO, - serialized_options=None, - create_key=_descriptor._internal_create_key, - ), - _descriptor.MethodDescriptor( - name="SetOption", - full_name="tendermint.abci.ABCIApplication.SetOption", - index=3, - containing_service=None, - input_type=_REQUESTSETOPTION, - output_type=_RESPONSESETOPTION, - serialized_options=None, - create_key=_descriptor._internal_create_key, - ), - _descriptor.MethodDescriptor( - name="DeliverTx", - full_name="tendermint.abci.ABCIApplication.DeliverTx", - index=4, - containing_service=None, - input_type=_REQUESTDELIVERTX, - output_type=_RESPONSEDELIVERTX, - serialized_options=None, - create_key=_descriptor._internal_create_key, - ), - _descriptor.MethodDescriptor( - name="CheckTx", - full_name="tendermint.abci.ABCIApplication.CheckTx", - index=5, - containing_service=None, - input_type=_REQUESTCHECKTX, - output_type=_RESPONSECHECKTX, - serialized_options=None, - create_key=_descriptor._internal_create_key, - ), - _descriptor.MethodDescriptor( - name="Query", - full_name="tendermint.abci.ABCIApplication.Query", - index=6, - containing_service=None, - input_type=_REQUESTQUERY, - output_type=_RESPONSEQUERY, - serialized_options=None, - create_key=_descriptor._internal_create_key, - ), - _descriptor.MethodDescriptor( - name="Commit", - full_name="tendermint.abci.ABCIApplication.Commit", - index=7, - containing_service=None, - input_type=_REQUESTCOMMIT, - output_type=_RESPONSECOMMIT, - serialized_options=None, - create_key=_descriptor._internal_create_key, - ), - _descriptor.MethodDescriptor( - name="InitChain", - full_name="tendermint.abci.ABCIApplication.InitChain", - index=8, - containing_service=None, - input_type=_REQUESTINITCHAIN, - output_type=_RESPONSEINITCHAIN, - serialized_options=None, - create_key=_descriptor._internal_create_key, - ), - _descriptor.MethodDescriptor( - name="BeginBlock", - full_name="tendermint.abci.ABCIApplication.BeginBlock", - index=9, - containing_service=None, - input_type=_REQUESTBEGINBLOCK, - output_type=_RESPONSEBEGINBLOCK, - serialized_options=None, - create_key=_descriptor._internal_create_key, - ), - _descriptor.MethodDescriptor( - name="EndBlock", - full_name="tendermint.abci.ABCIApplication.EndBlock", - index=10, - containing_service=None, - input_type=_REQUESTENDBLOCK, - output_type=_RESPONSEENDBLOCK, - serialized_options=None, - create_key=_descriptor._internal_create_key, - ), - _descriptor.MethodDescriptor( - name="ListSnapshots", - full_name="tendermint.abci.ABCIApplication.ListSnapshots", - index=11, - containing_service=None, - input_type=_REQUESTLISTSNAPSHOTS, - output_type=_RESPONSELISTSNAPSHOTS, - serialized_options=None, - create_key=_descriptor._internal_create_key, - ), - _descriptor.MethodDescriptor( - name="OfferSnapshot", - full_name="tendermint.abci.ABCIApplication.OfferSnapshot", - index=12, - containing_service=None, - input_type=_REQUESTOFFERSNAPSHOT, - output_type=_RESPONSEOFFERSNAPSHOT, - serialized_options=None, - create_key=_descriptor._internal_create_key, - ), - _descriptor.MethodDescriptor( - name="LoadSnapshotChunk", - full_name="tendermint.abci.ABCIApplication.LoadSnapshotChunk", - index=13, - containing_service=None, - input_type=_REQUESTLOADSNAPSHOTCHUNK, - output_type=_RESPONSELOADSNAPSHOTCHUNK, - serialized_options=None, - create_key=_descriptor._internal_create_key, - ), - _descriptor.MethodDescriptor( - name="ApplySnapshotChunk", - full_name="tendermint.abci.ABCIApplication.ApplySnapshotChunk", - index=14, - containing_service=None, - input_type=_REQUESTAPPLYSNAPSHOTCHUNK, - output_type=_RESPONSEAPPLYSNAPSHOTCHUNK, - serialized_options=None, - create_key=_descriptor._internal_create_key, - ), - ], -) -_sym_db.RegisterServiceDescriptor(_ABCIAPPLICATION) - -DESCRIPTOR.services_by_name["ABCIApplication"] = _ABCIAPPLICATION - +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile( + b'\n\x1btendermint/abci/types.proto\x12\x0ftendermint.abci\x1a\x1dtendermint/crypto/proof.proto\x1a\x1ctendermint/types/types.proto\x1a\x1ctendermint/crypto/keys.proto\x1a\x1dtendermint/types/params.proto\x1a\x1fgoogle/protobuf/timestamp.proto\x1a\x14gogoproto/gogo.proto"\xea\x06\n\x07Request\x12,\n\x04\x65\x63ho\x18\x01 \x01(\x0b\x32\x1c.tendermint.abci.RequestEchoH\x00\x12.\n\x05\x66lush\x18\x02 \x01(\x0b\x32\x1d.tendermint.abci.RequestFlushH\x00\x12,\n\x04info\x18\x03 \x01(\x0b\x32\x1c.tendermint.abci.RequestInfoH\x00\x12\x37\n\nset_option\x18\x04 \x01(\x0b\x32!.tendermint.abci.RequestSetOptionH\x00\x12\x37\n\ninit_chain\x18\x05 \x01(\x0b\x32!.tendermint.abci.RequestInitChainH\x00\x12.\n\x05query\x18\x06 \x01(\x0b\x32\x1d.tendermint.abci.RequestQueryH\x00\x12\x39\n\x0b\x62\x65gin_block\x18\x07 \x01(\x0b\x32".tendermint.abci.RequestBeginBlockH\x00\x12\x33\n\x08\x63heck_tx\x18\x08 \x01(\x0b\x32\x1f.tendermint.abci.RequestCheckTxH\x00\x12\x37\n\ndeliver_tx\x18\t \x01(\x0b\x32!.tendermint.abci.RequestDeliverTxH\x00\x12\x35\n\tend_block\x18\n \x01(\x0b\x32 .tendermint.abci.RequestEndBlockH\x00\x12\x30\n\x06\x63ommit\x18\x0b \x01(\x0b\x32\x1e.tendermint.abci.RequestCommitH\x00\x12?\n\x0elist_snapshots\x18\x0c \x01(\x0b\x32%.tendermint.abci.RequestListSnapshotsH\x00\x12?\n\x0eoffer_snapshot\x18\r \x01(\x0b\x32%.tendermint.abci.RequestOfferSnapshotH\x00\x12H\n\x13load_snapshot_chunk\x18\x0e \x01(\x0b\x32).tendermint.abci.RequestLoadSnapshotChunkH\x00\x12J\n\x14\x61pply_snapshot_chunk\x18\x0f \x01(\x0b\x32*.tendermint.abci.RequestApplySnapshotChunkH\x00\x42\x07\n\x05value"\x1e\n\x0bRequestEcho\x12\x0f\n\x07message\x18\x01 \x01(\t"\x0e\n\x0cRequestFlush"J\n\x0bRequestInfo\x12\x0f\n\x07version\x18\x01 \x01(\t\x12\x15\n\rblock_version\x18\x02 \x01(\x04\x12\x13\n\x0bp2p_version\x18\x03 \x01(\x04".\n\x10RequestSetOption\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t"\x81\x02\n\x10RequestInitChain\x12\x32\n\x04time\x18\x01 \x01(\x0b\x32\x1a.google.protobuf.TimestampB\x08\xc8\xde\x1f\x00\x90\xdf\x1f\x01\x12\x10\n\x08\x63hain_id\x18\x02 \x01(\t\x12:\n\x10\x63onsensus_params\x18\x03 \x01(\x0b\x32 .tendermint.abci.ConsensusParams\x12:\n\nvalidators\x18\x04 \x03(\x0b\x32 .tendermint.abci.ValidatorUpdateB\x04\xc8\xde\x1f\x00\x12\x17\n\x0f\x61pp_state_bytes\x18\x05 \x01(\x0c\x12\x16\n\x0einitial_height\x18\x06 \x01(\x03"I\n\x0cRequestQuery\x12\x0c\n\x04\x64\x61ta\x18\x01 \x01(\x0c\x12\x0c\n\x04path\x18\x02 \x01(\t\x12\x0e\n\x06height\x18\x03 \x01(\x03\x12\r\n\x05prove\x18\x04 \x01(\x08"\xd1\x01\n\x11RequestBeginBlock\x12\x0c\n\x04hash\x18\x01 \x01(\x0c\x12.\n\x06header\x18\x02 \x01(\x0b\x32\x18.tendermint.types.HeaderB\x04\xc8\xde\x1f\x00\x12?\n\x10last_commit_info\x18\x03 \x01(\x0b\x32\x1f.tendermint.abci.LastCommitInfoB\x04\xc8\xde\x1f\x00\x12=\n\x14\x62yzantine_validators\x18\x04 \x03(\x0b\x32\x19.tendermint.abci.EvidenceB\x04\xc8\xde\x1f\x00"H\n\x0eRequestCheckTx\x12\n\n\x02tx\x18\x01 \x01(\x0c\x12*\n\x04type\x18\x02 \x01(\x0e\x32\x1c.tendermint.abci.CheckTxType"\x1e\n\x10RequestDeliverTx\x12\n\n\x02tx\x18\x01 \x01(\x0c"!\n\x0fRequestEndBlock\x12\x0e\n\x06height\x18\x01 \x01(\x03"\x0f\n\rRequestCommit"\x16\n\x14RequestListSnapshots"U\n\x14RequestOfferSnapshot\x12+\n\x08snapshot\x18\x01 \x01(\x0b\x32\x19.tendermint.abci.Snapshot\x12\x10\n\x08\x61pp_hash\x18\x02 \x01(\x0c"I\n\x18RequestLoadSnapshotChunk\x12\x0e\n\x06height\x18\x01 \x01(\x04\x12\x0e\n\x06\x66ormat\x18\x02 \x01(\r\x12\r\n\x05\x63hunk\x18\x03 \x01(\r"I\n\x19RequestApplySnapshotChunk\x12\r\n\x05index\x18\x01 \x01(\r\x12\r\n\x05\x63hunk\x18\x02 \x01(\x0c\x12\x0e\n\x06sender\x18\x03 \x01(\t"\xb3\x07\n\x08Response\x12\x37\n\texception\x18\x01 \x01(\x0b\x32".tendermint.abci.ResponseExceptionH\x00\x12-\n\x04\x65\x63ho\x18\x02 \x01(\x0b\x32\x1d.tendermint.abci.ResponseEchoH\x00\x12/\n\x05\x66lush\x18\x03 \x01(\x0b\x32\x1e.tendermint.abci.ResponseFlushH\x00\x12-\n\x04info\x18\x04 \x01(\x0b\x32\x1d.tendermint.abci.ResponseInfoH\x00\x12\x38\n\nset_option\x18\x05 \x01(\x0b\x32".tendermint.abci.ResponseSetOptionH\x00\x12\x38\n\ninit_chain\x18\x06 \x01(\x0b\x32".tendermint.abci.ResponseInitChainH\x00\x12/\n\x05query\x18\x07 \x01(\x0b\x32\x1e.tendermint.abci.ResponseQueryH\x00\x12:\n\x0b\x62\x65gin_block\x18\x08 \x01(\x0b\x32#.tendermint.abci.ResponseBeginBlockH\x00\x12\x34\n\x08\x63heck_tx\x18\t \x01(\x0b\x32 .tendermint.abci.ResponseCheckTxH\x00\x12\x38\n\ndeliver_tx\x18\n \x01(\x0b\x32".tendermint.abci.ResponseDeliverTxH\x00\x12\x36\n\tend_block\x18\x0b \x01(\x0b\x32!.tendermint.abci.ResponseEndBlockH\x00\x12\x31\n\x06\x63ommit\x18\x0c \x01(\x0b\x32\x1f.tendermint.abci.ResponseCommitH\x00\x12@\n\x0elist_snapshots\x18\r \x01(\x0b\x32&.tendermint.abci.ResponseListSnapshotsH\x00\x12@\n\x0eoffer_snapshot\x18\x0e \x01(\x0b\x32&.tendermint.abci.ResponseOfferSnapshotH\x00\x12I\n\x13load_snapshot_chunk\x18\x0f \x01(\x0b\x32*.tendermint.abci.ResponseLoadSnapshotChunkH\x00\x12K\n\x14\x61pply_snapshot_chunk\x18\x10 \x01(\x0b\x32+.tendermint.abci.ResponseApplySnapshotChunkH\x00\x42\x07\n\x05value""\n\x11ResponseException\x12\r\n\x05\x65rror\x18\x01 \x01(\t"\x1f\n\x0cResponseEcho\x12\x0f\n\x07message\x18\x01 \x01(\t"\x0f\n\rResponseFlush"z\n\x0cResponseInfo\x12\x0c\n\x04\x64\x61ta\x18\x01 \x01(\t\x12\x0f\n\x07version\x18\x02 \x01(\t\x12\x13\n\x0b\x61pp_version\x18\x03 \x01(\x04\x12\x19\n\x11last_block_height\x18\x04 \x01(\x03\x12\x1b\n\x13last_block_app_hash\x18\x05 \x01(\x0c"<\n\x11ResponseSetOption\x12\x0c\n\x04\x63ode\x18\x01 \x01(\r\x12\x0b\n\x03log\x18\x03 \x01(\t\x12\x0c\n\x04info\x18\x04 \x01(\t"\x9d\x01\n\x11ResponseInitChain\x12:\n\x10\x63onsensus_params\x18\x01 \x01(\x0b\x32 .tendermint.abci.ConsensusParams\x12:\n\nvalidators\x18\x02 \x03(\x0b\x32 .tendermint.abci.ValidatorUpdateB\x04\xc8\xde\x1f\x00\x12\x10\n\x08\x61pp_hash\x18\x03 \x01(\x0c"\xb6\x01\n\rResponseQuery\x12\x0c\n\x04\x63ode\x18\x01 \x01(\r\x12\x0b\n\x03log\x18\x03 \x01(\t\x12\x0c\n\x04info\x18\x04 \x01(\t\x12\r\n\x05index\x18\x05 \x01(\x03\x12\x0b\n\x03key\x18\x06 \x01(\x0c\x12\r\n\x05value\x18\x07 \x01(\x0c\x12.\n\tproof_ops\x18\x08 \x01(\x0b\x32\x1b.tendermint.crypto.ProofOps\x12\x0e\n\x06height\x18\t \x01(\x03\x12\x11\n\tcodespace\x18\n \x01(\t"V\n\x12ResponseBeginBlock\x12@\n\x06\x65vents\x18\x01 \x03(\x0b\x32\x16.tendermint.abci.EventB\x18\xc8\xde\x1f\x00\xea\xde\x1f\x10\x65vents,omitempty"\xd9\x01\n\x0fResponseCheckTx\x12\x0c\n\x04\x63ode\x18\x01 \x01(\r\x12\x0c\n\x04\x64\x61ta\x18\x02 \x01(\x0c\x12\x0b\n\x03log\x18\x03 \x01(\t\x12\x0c\n\x04info\x18\x04 \x01(\t\x12\x1e\n\ngas_wanted\x18\x05 \x01(\x03R\ngas_wanted\x12\x1a\n\x08gas_used\x18\x06 \x01(\x03R\x08gas_used\x12@\n\x06\x65vents\x18\x07 \x03(\x0b\x32\x16.tendermint.abci.EventB\x18\xc8\xde\x1f\x00\xea\xde\x1f\x10\x65vents,omitempty\x12\x11\n\tcodespace\x18\x08 \x01(\t"\xdb\x01\n\x11ResponseDeliverTx\x12\x0c\n\x04\x63ode\x18\x01 \x01(\r\x12\x0c\n\x04\x64\x61ta\x18\x02 \x01(\x0c\x12\x0b\n\x03log\x18\x03 \x01(\t\x12\x0c\n\x04info\x18\x04 \x01(\t\x12\x1e\n\ngas_wanted\x18\x05 \x01(\x03R\ngas_wanted\x12\x1a\n\x08gas_used\x18\x06 \x01(\x03R\x08gas_used\x12@\n\x06\x65vents\x18\x07 \x03(\x0b\x32\x16.tendermint.abci.EventB\x18\xc8\xde\x1f\x00\xea\xde\x1f\x10\x65vents,omitempty\x12\x11\n\tcodespace\x18\x08 \x01(\t"\xda\x01\n\x10ResponseEndBlock\x12\x41\n\x11validator_updates\x18\x01 \x03(\x0b\x32 .tendermint.abci.ValidatorUpdateB\x04\xc8\xde\x1f\x00\x12\x41\n\x17\x63onsensus_param_updates\x18\x02 \x01(\x0b\x32 .tendermint.abci.ConsensusParams\x12@\n\x06\x65vents\x18\x03 \x03(\x0b\x32\x16.tendermint.abci.EventB\x18\xc8\xde\x1f\x00\xea\xde\x1f\x10\x65vents,omitempty"5\n\x0eResponseCommit\x12\x0c\n\x04\x64\x61ta\x18\x02 \x01(\x0c\x12\x15\n\rretain_height\x18\x03 \x01(\x03"E\n\x15ResponseListSnapshots\x12,\n\tsnapshots\x18\x01 \x03(\x0b\x32\x19.tendermint.abci.Snapshot"\xb6\x01\n\x15ResponseOfferSnapshot\x12=\n\x06result\x18\x01 \x01(\x0e\x32-.tendermint.abci.ResponseOfferSnapshot.Result"^\n\x06Result\x12\x0b\n\x07UNKNOWN\x10\x00\x12\n\n\x06\x41\x43\x43\x45PT\x10\x01\x12\t\n\x05\x41\x42ORT\x10\x02\x12\n\n\x06REJECT\x10\x03\x12\x11\n\rREJECT_FORMAT\x10\x04\x12\x11\n\rREJECT_SENDER\x10\x05"*\n\x19ResponseLoadSnapshotChunk\x12\r\n\x05\x63hunk\x18\x01 \x01(\x0c"\xf2\x01\n\x1aResponseApplySnapshotChunk\x12\x42\n\x06result\x18\x01 \x01(\x0e\x32\x32.tendermint.abci.ResponseApplySnapshotChunk.Result\x12\x16\n\x0erefetch_chunks\x18\x02 \x03(\r\x12\x16\n\x0ereject_senders\x18\x03 \x03(\t"`\n\x06Result\x12\x0b\n\x07UNKNOWN\x10\x00\x12\n\n\x06\x41\x43\x43\x45PT\x10\x01\x12\t\n\x05\x41\x42ORT\x10\x02\x12\t\n\x05RETRY\x10\x03\x12\x12\n\x0eRETRY_SNAPSHOT\x10\x04\x12\x13\n\x0fREJECT_SNAPSHOT\x10\x05"\xda\x01\n\x0f\x43onsensusParams\x12+\n\x05\x62lock\x18\x01 \x01(\x0b\x32\x1c.tendermint.abci.BlockParams\x12\x32\n\x08\x65vidence\x18\x02 \x01(\x0b\x32 .tendermint.types.EvidenceParams\x12\x34\n\tvalidator\x18\x03 \x01(\x0b\x32!.tendermint.types.ValidatorParams\x12\x30\n\x07version\x18\x04 \x01(\x0b\x32\x1f.tendermint.types.VersionParams"1\n\x0b\x42lockParams\x12\x11\n\tmax_bytes\x18\x01 \x01(\x03\x12\x0f\n\x07max_gas\x18\x02 \x01(\x03"O\n\x0eLastCommitInfo\x12\r\n\x05round\x18\x01 \x01(\x05\x12.\n\x05votes\x18\x02 \x03(\x0b\x32\x19.tendermint.abci.VoteInfoB\x04\xc8\xde\x1f\x00"h\n\x05\x45vent\x12\x0c\n\x04type\x18\x01 \x01(\t\x12Q\n\nattributes\x18\x02 \x03(\x0b\x32\x1f.tendermint.abci.EventAttributeB\x1c\xc8\xde\x1f\x00\xea\xde\x1f\x14\x61ttributes,omitempty";\n\x0e\x45ventAttribute\x12\x0b\n\x03key\x18\x01 \x01(\x0c\x12\r\n\x05value\x18\x02 \x01(\x0c\x12\r\n\x05index\x18\x03 \x01(\x08"o\n\x08TxResult\x12\x0e\n\x06height\x18\x01 \x01(\x03\x12\r\n\x05index\x18\x02 \x01(\r\x12\n\n\x02tx\x18\x03 \x01(\x0c\x12\x38\n\x06result\x18\x04 \x01(\x0b\x32".tendermint.abci.ResponseDeliverTxB\x04\xc8\xde\x1f\x00"+\n\tValidator\x12\x0f\n\x07\x61\x64\x64ress\x18\x01 \x01(\x0c\x12\r\n\x05power\x18\x03 \x01(\x03"U\n\x0fValidatorUpdate\x12\x33\n\x07pub_key\x18\x01 \x01(\x0b\x32\x1c.tendermint.crypto.PublicKeyB\x04\xc8\xde\x1f\x00\x12\r\n\x05power\x18\x02 \x01(\x03"Z\n\x08VoteInfo\x12\x33\n\tvalidator\x18\x01 \x01(\x0b\x32\x1a.tendermint.abci.ValidatorB\x04\xc8\xde\x1f\x00\x12\x19\n\x11signed_last_block\x18\x02 \x01(\x08"\xcc\x01\n\x08\x45vidence\x12+\n\x04type\x18\x01 \x01(\x0e\x32\x1d.tendermint.abci.EvidenceType\x12\x33\n\tvalidator\x18\x02 \x01(\x0b\x32\x1a.tendermint.abci.ValidatorB\x04\xc8\xde\x1f\x00\x12\x0e\n\x06height\x18\x03 \x01(\x03\x12\x32\n\x04time\x18\x04 \x01(\x0b\x32\x1a.google.protobuf.TimestampB\x08\xc8\xde\x1f\x00\x90\xdf\x1f\x01\x12\x1a\n\x12total_voting_power\x18\x05 \x01(\x03"Z\n\x08Snapshot\x12\x0e\n\x06height\x18\x01 \x01(\x04\x12\x0e\n\x06\x66ormat\x18\x02 \x01(\r\x12\x0e\n\x06\x63hunks\x18\x03 \x01(\r\x12\x0c\n\x04hash\x18\x04 \x01(\x0c\x12\x10\n\x08metadata\x18\x05 \x01(\x0c*9\n\x0b\x43heckTxType\x12\x10\n\x03NEW\x10\x00\x1a\x07\x8a\x9d \x03New\x12\x18\n\x07RECHECK\x10\x01\x1a\x0b\x8a\x9d \x07Recheck*H\n\x0c\x45videnceType\x12\x0b\n\x07UNKNOWN\x10\x00\x12\x12\n\x0e\x44UPLICATE_VOTE\x10\x01\x12\x17\n\x13LIGHT_CLIENT_ATTACK\x10\x02\x32\x83\n\n\x0f\x41\x42\x43IApplication\x12\x43\n\x04\x45\x63ho\x12\x1c.tendermint.abci.RequestEcho\x1a\x1d.tendermint.abci.ResponseEcho\x12\x46\n\x05\x46lush\x12\x1d.tendermint.abci.RequestFlush\x1a\x1e.tendermint.abci.ResponseFlush\x12\x43\n\x04Info\x12\x1c.tendermint.abci.RequestInfo\x1a\x1d.tendermint.abci.ResponseInfo\x12R\n\tSetOption\x12!.tendermint.abci.RequestSetOption\x1a".tendermint.abci.ResponseSetOption\x12R\n\tDeliverTx\x12!.tendermint.abci.RequestDeliverTx\x1a".tendermint.abci.ResponseDeliverTx\x12L\n\x07\x43heckTx\x12\x1f.tendermint.abci.RequestCheckTx\x1a .tendermint.abci.ResponseCheckTx\x12\x46\n\x05Query\x12\x1d.tendermint.abci.RequestQuery\x1a\x1e.tendermint.abci.ResponseQuery\x12I\n\x06\x43ommit\x12\x1e.tendermint.abci.RequestCommit\x1a\x1f.tendermint.abci.ResponseCommit\x12R\n\tInitChain\x12!.tendermint.abci.RequestInitChain\x1a".tendermint.abci.ResponseInitChain\x12U\n\nBeginBlock\x12".tendermint.abci.RequestBeginBlock\x1a#.tendermint.abci.ResponseBeginBlock\x12O\n\x08\x45ndBlock\x12 .tendermint.abci.RequestEndBlock\x1a!.tendermint.abci.ResponseEndBlock\x12^\n\rListSnapshots\x12%.tendermint.abci.RequestListSnapshots\x1a&.tendermint.abci.ResponseListSnapshots\x12^\n\rOfferSnapshot\x12%.tendermint.abci.RequestOfferSnapshot\x1a&.tendermint.abci.ResponseOfferSnapshot\x12j\n\x11LoadSnapshotChunk\x12).tendermint.abci.RequestLoadSnapshotChunk\x1a*.tendermint.abci.ResponseLoadSnapshotChunk\x12m\n\x12\x41pplySnapshotChunk\x12*.tendermint.abci.RequestApplySnapshotChunk\x1a+.tendermint.abci.ResponseApplySnapshotChunkB-Z+github.com/tendermint/tendermint/abci/typesb\x06proto3' +) + +_globals = globals() +_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) +_builder.BuildTopDescriptorsAndMessages( + DESCRIPTOR, "tendermint.abci.types_pb2", _globals +) +if _descriptor._USE_C_DESCRIPTORS == False: + DESCRIPTOR._options = None + DESCRIPTOR._serialized_options = b"Z+github.com/tendermint/tendermint/abci/types" + _CHECKTXTYPE.values_by_name["NEW"]._options = None + _CHECKTXTYPE.values_by_name["NEW"]._serialized_options = b"\212\235 \003New" + _CHECKTXTYPE.values_by_name["RECHECK"]._options = None + _CHECKTXTYPE.values_by_name["RECHECK"]._serialized_options = b"\212\235 \007Recheck" + _REQUESTINITCHAIN.fields_by_name["time"]._options = None + _REQUESTINITCHAIN.fields_by_name[ + "time" + ]._serialized_options = b"\310\336\037\000\220\337\037\001" + _REQUESTINITCHAIN.fields_by_name["validators"]._options = None + _REQUESTINITCHAIN.fields_by_name[ + "validators" + ]._serialized_options = b"\310\336\037\000" + _REQUESTBEGINBLOCK.fields_by_name["header"]._options = None + _REQUESTBEGINBLOCK.fields_by_name[ + "header" + ]._serialized_options = b"\310\336\037\000" + _REQUESTBEGINBLOCK.fields_by_name["last_commit_info"]._options = None + _REQUESTBEGINBLOCK.fields_by_name[ + "last_commit_info" + ]._serialized_options = b"\310\336\037\000" + _REQUESTBEGINBLOCK.fields_by_name["byzantine_validators"]._options = None + _REQUESTBEGINBLOCK.fields_by_name[ + "byzantine_validators" + ]._serialized_options = b"\310\336\037\000" + _RESPONSEINITCHAIN.fields_by_name["validators"]._options = None + _RESPONSEINITCHAIN.fields_by_name[ + "validators" + ]._serialized_options = b"\310\336\037\000" + _RESPONSEBEGINBLOCK.fields_by_name["events"]._options = None + _RESPONSEBEGINBLOCK.fields_by_name[ + "events" + ]._serialized_options = b"\310\336\037\000\352\336\037\020events,omitempty" + _RESPONSECHECKTX.fields_by_name["events"]._options = None + _RESPONSECHECKTX.fields_by_name[ + "events" + ]._serialized_options = b"\310\336\037\000\352\336\037\020events,omitempty" + _RESPONSEDELIVERTX.fields_by_name["events"]._options = None + _RESPONSEDELIVERTX.fields_by_name[ + "events" + ]._serialized_options = b"\310\336\037\000\352\336\037\020events,omitempty" + _RESPONSEENDBLOCK.fields_by_name["validator_updates"]._options = None + _RESPONSEENDBLOCK.fields_by_name[ + "validator_updates" + ]._serialized_options = b"\310\336\037\000" + _RESPONSEENDBLOCK.fields_by_name["events"]._options = None + _RESPONSEENDBLOCK.fields_by_name[ + "events" + ]._serialized_options = b"\310\336\037\000\352\336\037\020events,omitempty" + _LASTCOMMITINFO.fields_by_name["votes"]._options = None + _LASTCOMMITINFO.fields_by_name["votes"]._serialized_options = b"\310\336\037\000" + _EVENT.fields_by_name["attributes"]._options = None + _EVENT.fields_by_name[ + "attributes" + ]._serialized_options = b"\310\336\037\000\352\336\037\024attributes,omitempty" + _TXRESULT.fields_by_name["result"]._options = None + _TXRESULT.fields_by_name["result"]._serialized_options = b"\310\336\037\000" + _VALIDATORUPDATE.fields_by_name["pub_key"]._options = None + _VALIDATORUPDATE.fields_by_name["pub_key"]._serialized_options = b"\310\336\037\000" + _VOTEINFO.fields_by_name["validator"]._options = None + _VOTEINFO.fields_by_name["validator"]._serialized_options = b"\310\336\037\000" + _EVIDENCE.fields_by_name["validator"]._options = None + _EVIDENCE.fields_by_name["validator"]._serialized_options = b"\310\336\037\000" + _EVIDENCE.fields_by_name["time"]._options = None + _EVIDENCE.fields_by_name[ + "time" + ]._serialized_options = b"\310\336\037\000\220\337\037\001" + _globals["_CHECKTXTYPE"]._serialized_start = 6314 + _globals["_CHECKTXTYPE"]._serialized_end = 6371 + _globals["_EVIDENCETYPE"]._serialized_start = 6373 + _globals["_EVIDENCETYPE"]._serialized_end = 6445 + _globals["_REQUEST"]._serialized_start = 226 + _globals["_REQUEST"]._serialized_end = 1100 + _globals["_REQUESTECHO"]._serialized_start = 1102 + _globals["_REQUESTECHO"]._serialized_end = 1132 + _globals["_REQUESTFLUSH"]._serialized_start = 1134 + _globals["_REQUESTFLUSH"]._serialized_end = 1148 + _globals["_REQUESTINFO"]._serialized_start = 1150 + _globals["_REQUESTINFO"]._serialized_end = 1224 + _globals["_REQUESTSETOPTION"]._serialized_start = 1226 + _globals["_REQUESTSETOPTION"]._serialized_end = 1272 + _globals["_REQUESTINITCHAIN"]._serialized_start = 1275 + _globals["_REQUESTINITCHAIN"]._serialized_end = 1532 + _globals["_REQUESTQUERY"]._serialized_start = 1534 + _globals["_REQUESTQUERY"]._serialized_end = 1607 + _globals["_REQUESTBEGINBLOCK"]._serialized_start = 1610 + _globals["_REQUESTBEGINBLOCK"]._serialized_end = 1819 + _globals["_REQUESTCHECKTX"]._serialized_start = 1821 + _globals["_REQUESTCHECKTX"]._serialized_end = 1893 + _globals["_REQUESTDELIVERTX"]._serialized_start = 1895 + _globals["_REQUESTDELIVERTX"]._serialized_end = 1925 + _globals["_REQUESTENDBLOCK"]._serialized_start = 1927 + _globals["_REQUESTENDBLOCK"]._serialized_end = 1960 + _globals["_REQUESTCOMMIT"]._serialized_start = 1962 + _globals["_REQUESTCOMMIT"]._serialized_end = 1977 + _globals["_REQUESTLISTSNAPSHOTS"]._serialized_start = 1979 + _globals["_REQUESTLISTSNAPSHOTS"]._serialized_end = 2001 + _globals["_REQUESTOFFERSNAPSHOT"]._serialized_start = 2003 + _globals["_REQUESTOFFERSNAPSHOT"]._serialized_end = 2088 + _globals["_REQUESTLOADSNAPSHOTCHUNK"]._serialized_start = 2090 + _globals["_REQUESTLOADSNAPSHOTCHUNK"]._serialized_end = 2163 + _globals["_REQUESTAPPLYSNAPSHOTCHUNK"]._serialized_start = 2165 + _globals["_REQUESTAPPLYSNAPSHOTCHUNK"]._serialized_end = 2238 + _globals["_RESPONSE"]._serialized_start = 2241 + _globals["_RESPONSE"]._serialized_end = 3188 + _globals["_RESPONSEEXCEPTION"]._serialized_start = 3190 + _globals["_RESPONSEEXCEPTION"]._serialized_end = 3224 + _globals["_RESPONSEECHO"]._serialized_start = 3226 + _globals["_RESPONSEECHO"]._serialized_end = 3257 + _globals["_RESPONSEFLUSH"]._serialized_start = 3259 + _globals["_RESPONSEFLUSH"]._serialized_end = 3274 + _globals["_RESPONSEINFO"]._serialized_start = 3276 + _globals["_RESPONSEINFO"]._serialized_end = 3398 + _globals["_RESPONSESETOPTION"]._serialized_start = 3400 + _globals["_RESPONSESETOPTION"]._serialized_end = 3460 + _globals["_RESPONSEINITCHAIN"]._serialized_start = 3463 + _globals["_RESPONSEINITCHAIN"]._serialized_end = 3620 + _globals["_RESPONSEQUERY"]._serialized_start = 3623 + _globals["_RESPONSEQUERY"]._serialized_end = 3805 + _globals["_RESPONSEBEGINBLOCK"]._serialized_start = 3807 + _globals["_RESPONSEBEGINBLOCK"]._serialized_end = 3893 + _globals["_RESPONSECHECKTX"]._serialized_start = 3896 + _globals["_RESPONSECHECKTX"]._serialized_end = 4113 + _globals["_RESPONSEDELIVERTX"]._serialized_start = 4116 + _globals["_RESPONSEDELIVERTX"]._serialized_end = 4335 + _globals["_RESPONSEENDBLOCK"]._serialized_start = 4338 + _globals["_RESPONSEENDBLOCK"]._serialized_end = 4556 + _globals["_RESPONSECOMMIT"]._serialized_start = 4558 + _globals["_RESPONSECOMMIT"]._serialized_end = 4611 + _globals["_RESPONSELISTSNAPSHOTS"]._serialized_start = 4613 + _globals["_RESPONSELISTSNAPSHOTS"]._serialized_end = 4682 + _globals["_RESPONSEOFFERSNAPSHOT"]._serialized_start = 4685 + _globals["_RESPONSEOFFERSNAPSHOT"]._serialized_end = 4867 + _globals["_RESPONSEOFFERSNAPSHOT_RESULT"]._serialized_start = 4773 + _globals["_RESPONSEOFFERSNAPSHOT_RESULT"]._serialized_end = 4867 + _globals["_RESPONSELOADSNAPSHOTCHUNK"]._serialized_start = 4869 + _globals["_RESPONSELOADSNAPSHOTCHUNK"]._serialized_end = 4911 + _globals["_RESPONSEAPPLYSNAPSHOTCHUNK"]._serialized_start = 4914 + _globals["_RESPONSEAPPLYSNAPSHOTCHUNK"]._serialized_end = 5156 + _globals["_RESPONSEAPPLYSNAPSHOTCHUNK_RESULT"]._serialized_start = 5060 + _globals["_RESPONSEAPPLYSNAPSHOTCHUNK_RESULT"]._serialized_end = 5156 + _globals["_CONSENSUSPARAMS"]._serialized_start = 5159 + _globals["_CONSENSUSPARAMS"]._serialized_end = 5377 + _globals["_BLOCKPARAMS"]._serialized_start = 5379 + _globals["_BLOCKPARAMS"]._serialized_end = 5428 + _globals["_LASTCOMMITINFO"]._serialized_start = 5430 + _globals["_LASTCOMMITINFO"]._serialized_end = 5509 + _globals["_EVENT"]._serialized_start = 5511 + _globals["_EVENT"]._serialized_end = 5615 + _globals["_EVENTATTRIBUTE"]._serialized_start = 5617 + _globals["_EVENTATTRIBUTE"]._serialized_end = 5676 + _globals["_TXRESULT"]._serialized_start = 5678 + _globals["_TXRESULT"]._serialized_end = 5789 + _globals["_VALIDATOR"]._serialized_start = 5791 + _globals["_VALIDATOR"]._serialized_end = 5834 + _globals["_VALIDATORUPDATE"]._serialized_start = 5836 + _globals["_VALIDATORUPDATE"]._serialized_end = 5921 + _globals["_VOTEINFO"]._serialized_start = 5923 + _globals["_VOTEINFO"]._serialized_end = 6013 + _globals["_EVIDENCE"]._serialized_start = 6016 + _globals["_EVIDENCE"]._serialized_end = 6220 + _globals["_SNAPSHOT"]._serialized_start = 6222 + _globals["_SNAPSHOT"]._serialized_end = 6312 + _globals["_ABCIAPPLICATION"]._serialized_start = 6448 + _globals["_ABCIAPPLICATION"]._serialized_end = 7731 # @@protoc_insertion_point(module_scope) diff --git a/packages/valory/connections/abci/tendermint/crypto/keys_pb2.py b/packages/valory/connections/abci/tendermint/crypto/keys_pb2.py index caa4261a3a..dc00b90088 100644 --- a/packages/valory/connections/abci/tendermint/crypto/keys_pb2.py +++ b/packages/valory/connections/abci/tendermint/crypto/keys_pb2.py @@ -3,9 +3,9 @@ # source: tendermint/crypto/keys.proto """Generated protocol buffer code.""" from google.protobuf import descriptor as _descriptor -from google.protobuf import message as _message -from google.protobuf import reflection as _reflection +from google.protobuf import descriptor_pool as _descriptor_pool from google.protobuf import symbol_database as _symbol_database +from google.protobuf.internal import builder as _builder # @@protoc_insertion_point(imports) @@ -18,108 +18,22 @@ ) -DESCRIPTOR = _descriptor.FileDescriptor( - name="tendermint/crypto/keys.proto", - package="tendermint.crypto", - syntax="proto3", - serialized_options=b"Z8github.com/tendermint/tendermint/proto/tendermint/crypto", - create_key=_descriptor._internal_create_key, - serialized_pb=b'\n\x1ctendermint/crypto/keys.proto\x12\x11tendermint.crypto\x1a\x14gogoproto/gogo.proto"D\n\tPublicKey\x12\x11\n\x07\x65\x64\x32\x35\x35\x31\x39\x18\x01 \x01(\x0cH\x00\x12\x13\n\tsecp256k1\x18\x02 \x01(\x0cH\x00:\x08\xe8\xa1\x1f\x01\xe8\xa0\x1f\x01\x42\x05\n\x03sumB:Z8github.com/tendermint/tendermint/proto/tendermint/cryptob\x06proto3', - dependencies=[ - gogoproto_dot_gogo__pb2.DESCRIPTOR, - ], +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile( + b'\n\x1ctendermint/crypto/keys.proto\x12\x11tendermint.crypto\x1a\x14gogoproto/gogo.proto"D\n\tPublicKey\x12\x11\n\x07\x65\x64\x32\x35\x35\x31\x39\x18\x01 \x01(\x0cH\x00\x12\x13\n\tsecp256k1\x18\x02 \x01(\x0cH\x00:\x08\xe8\xa0\x1f\x01\xe8\xa1\x1f\x01\x42\x05\n\x03sumB:Z8github.com/tendermint/tendermint/proto/tendermint/cryptob\x06proto3' ) - -_PUBLICKEY = _descriptor.Descriptor( - name="PublicKey", - full_name="tendermint.crypto.PublicKey", - filename=None, - file=DESCRIPTOR, - containing_type=None, - create_key=_descriptor._internal_create_key, - fields=[ - _descriptor.FieldDescriptor( - name="ed25519", - full_name="tendermint.crypto.PublicKey.ed25519", - index=0, - number=1, - type=12, - cpp_type=9, - label=1, - has_default_value=False, - default_value=b"", - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="secp256k1", - full_name="tendermint.crypto.PublicKey.secp256k1", - index=1, - number=2, - type=12, - cpp_type=9, - label=1, - has_default_value=False, - default_value=b"", - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - ], - extensions=[], - nested_types=[], - enum_types=[], - serialized_options=b"\350\241\037\001\350\240\037\001", - is_extendable=False, - syntax="proto3", - extension_ranges=[], - oneofs=[ - _descriptor.OneofDescriptor( - name="sum", - full_name="tendermint.crypto.PublicKey.sum", - index=0, - containing_type=None, - create_key=_descriptor._internal_create_key, - fields=[], - ), - ], - serialized_start=73, - serialized_end=141, -) - -_PUBLICKEY.oneofs_by_name["sum"].fields.append(_PUBLICKEY.fields_by_name["ed25519"]) -_PUBLICKEY.fields_by_name["ed25519"].containing_oneof = _PUBLICKEY.oneofs_by_name["sum"] -_PUBLICKEY.oneofs_by_name["sum"].fields.append(_PUBLICKEY.fields_by_name["secp256k1"]) -_PUBLICKEY.fields_by_name["secp256k1"].containing_oneof = _PUBLICKEY.oneofs_by_name[ - "sum" -] -DESCRIPTOR.message_types_by_name["PublicKey"] = _PUBLICKEY -_sym_db.RegisterFileDescriptor(DESCRIPTOR) - -PublicKey = _reflection.GeneratedProtocolMessageType( - "PublicKey", - (_message.Message,), - { - "DESCRIPTOR": _PUBLICKEY, - "__module__": "tendermint.crypto.keys_pb2" - # @@protoc_insertion_point(class_scope:tendermint.crypto.PublicKey) - }, +_globals = globals() +_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) +_builder.BuildTopDescriptorsAndMessages( + DESCRIPTOR, "tendermint.crypto.keys_pb2", _globals ) -_sym_db.RegisterMessage(PublicKey) - - -DESCRIPTOR._options = None -_PUBLICKEY._options = None +if _descriptor._USE_C_DESCRIPTORS == False: + DESCRIPTOR._options = None + DESCRIPTOR._serialized_options = ( + b"Z8github.com/tendermint/tendermint/proto/tendermint/crypto" + ) + _PUBLICKEY._options = None + _PUBLICKEY._serialized_options = b"\350\240\037\001\350\241\037\001" + _globals["_PUBLICKEY"]._serialized_start = 73 + _globals["_PUBLICKEY"]._serialized_end = 141 # @@protoc_insertion_point(module_scope) diff --git a/packages/valory/connections/abci/tendermint/crypto/proof_pb2.py b/packages/valory/connections/abci/tendermint/crypto/proof_pb2.py index 75050371a3..adf30b16e7 100644 --- a/packages/valory/connections/abci/tendermint/crypto/proof_pb2.py +++ b/packages/valory/connections/abci/tendermint/crypto/proof_pb2.py @@ -3,9 +3,9 @@ # source: tendermint/crypto/proof.proto """Generated protocol buffer code.""" from google.protobuf import descriptor as _descriptor -from google.protobuf import message as _message -from google.protobuf import reflection as _reflection +from google.protobuf import descriptor_pool as _descriptor_pool from google.protobuf import symbol_database as _symbol_database +from google.protobuf.internal import builder as _builder # @@protoc_insertion_point(imports) @@ -18,440 +18,30 @@ ) -DESCRIPTOR = _descriptor.FileDescriptor( - name="tendermint/crypto/proof.proto", - package="tendermint.crypto", - syntax="proto3", - serialized_options=b"Z8github.com/tendermint/tendermint/proto/tendermint/crypto", - create_key=_descriptor._internal_create_key, - serialized_pb=b'\n\x1dtendermint/crypto/proof.proto\x12\x11tendermint.crypto\x1a\x14gogoproto/gogo.proto"G\n\x05Proof\x12\r\n\x05total\x18\x01 \x01(\x03\x12\r\n\x05index\x18\x02 \x01(\x03\x12\x11\n\tleaf_hash\x18\x03 \x01(\x0c\x12\r\n\x05\x61unts\x18\x04 \x03(\x0c"?\n\x07ValueOp\x12\x0b\n\x03key\x18\x01 \x01(\x0c\x12\'\n\x05proof\x18\x02 \x01(\x0b\x32\x18.tendermint.crypto.Proof"6\n\x08\x44ominoOp\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05input\x18\x02 \x01(\t\x12\x0e\n\x06output\x18\x03 \x01(\t"2\n\x07ProofOp\x12\x0c\n\x04type\x18\x01 \x01(\t\x12\x0b\n\x03key\x18\x02 \x01(\x0c\x12\x0c\n\x04\x64\x61ta\x18\x03 \x01(\x0c"9\n\x08ProofOps\x12-\n\x03ops\x18\x01 \x03(\x0b\x32\x1a.tendermint.crypto.ProofOpB\x04\xc8\xde\x1f\x00\x42:Z8github.com/tendermint/tendermint/proto/tendermint/cryptob\x06proto3', - dependencies=[ - gogoproto_dot_gogo__pb2.DESCRIPTOR, - ], -) - - -_PROOF = _descriptor.Descriptor( - name="Proof", - full_name="tendermint.crypto.Proof", - filename=None, - file=DESCRIPTOR, - containing_type=None, - create_key=_descriptor._internal_create_key, - fields=[ - _descriptor.FieldDescriptor( - name="total", - full_name="tendermint.crypto.Proof.total", - index=0, - number=1, - type=3, - cpp_type=2, - label=1, - has_default_value=False, - default_value=0, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="index", - full_name="tendermint.crypto.Proof.index", - index=1, - number=2, - type=3, - cpp_type=2, - label=1, - has_default_value=False, - default_value=0, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="leaf_hash", - full_name="tendermint.crypto.Proof.leaf_hash", - index=2, - number=3, - type=12, - cpp_type=9, - label=1, - has_default_value=False, - default_value=b"", - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="aunts", - full_name="tendermint.crypto.Proof.aunts", - index=3, - number=4, - type=12, - cpp_type=9, - label=3, - has_default_value=False, - default_value=[], - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - ], - extensions=[], - nested_types=[], - enum_types=[], - serialized_options=None, - is_extendable=False, - syntax="proto3", - extension_ranges=[], - oneofs=[], - serialized_start=74, - serialized_end=145, -) - - -_VALUEOP = _descriptor.Descriptor( - name="ValueOp", - full_name="tendermint.crypto.ValueOp", - filename=None, - file=DESCRIPTOR, - containing_type=None, - create_key=_descriptor._internal_create_key, - fields=[ - _descriptor.FieldDescriptor( - name="key", - full_name="tendermint.crypto.ValueOp.key", - index=0, - number=1, - type=12, - cpp_type=9, - label=1, - has_default_value=False, - default_value=b"", - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="proof", - full_name="tendermint.crypto.ValueOp.proof", - index=1, - number=2, - type=11, - cpp_type=10, - label=1, - has_default_value=False, - default_value=None, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - ], - extensions=[], - nested_types=[], - enum_types=[], - serialized_options=None, - is_extendable=False, - syntax="proto3", - extension_ranges=[], - oneofs=[], - serialized_start=147, - serialized_end=210, -) - - -_DOMINOOP = _descriptor.Descriptor( - name="DominoOp", - full_name="tendermint.crypto.DominoOp", - filename=None, - file=DESCRIPTOR, - containing_type=None, - create_key=_descriptor._internal_create_key, - fields=[ - _descriptor.FieldDescriptor( - name="key", - full_name="tendermint.crypto.DominoOp.key", - index=0, - number=1, - type=9, - cpp_type=9, - label=1, - has_default_value=False, - default_value=b"".decode("utf-8"), - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="input", - full_name="tendermint.crypto.DominoOp.input", - index=1, - number=2, - type=9, - cpp_type=9, - label=1, - has_default_value=False, - default_value=b"".decode("utf-8"), - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="output", - full_name="tendermint.crypto.DominoOp.output", - index=2, - number=3, - type=9, - cpp_type=9, - label=1, - has_default_value=False, - default_value=b"".decode("utf-8"), - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - ], - extensions=[], - nested_types=[], - enum_types=[], - serialized_options=None, - is_extendable=False, - syntax="proto3", - extension_ranges=[], - oneofs=[], - serialized_start=212, - serialized_end=266, -) - - -_PROOFOP = _descriptor.Descriptor( - name="ProofOp", - full_name="tendermint.crypto.ProofOp", - filename=None, - file=DESCRIPTOR, - containing_type=None, - create_key=_descriptor._internal_create_key, - fields=[ - _descriptor.FieldDescriptor( - name="type", - full_name="tendermint.crypto.ProofOp.type", - index=0, - number=1, - type=9, - cpp_type=9, - label=1, - has_default_value=False, - default_value=b"".decode("utf-8"), - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="key", - full_name="tendermint.crypto.ProofOp.key", - index=1, - number=2, - type=12, - cpp_type=9, - label=1, - has_default_value=False, - default_value=b"", - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="data", - full_name="tendermint.crypto.ProofOp.data", - index=2, - number=3, - type=12, - cpp_type=9, - label=1, - has_default_value=False, - default_value=b"", - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - ], - extensions=[], - nested_types=[], - enum_types=[], - serialized_options=None, - is_extendable=False, - syntax="proto3", - extension_ranges=[], - oneofs=[], - serialized_start=268, - serialized_end=318, -) - - -_PROOFOPS = _descriptor.Descriptor( - name="ProofOps", - full_name="tendermint.crypto.ProofOps", - filename=None, - file=DESCRIPTOR, - containing_type=None, - create_key=_descriptor._internal_create_key, - fields=[ - _descriptor.FieldDescriptor( - name="ops", - full_name="tendermint.crypto.ProofOps.ops", - index=0, - number=1, - type=11, - cpp_type=10, - label=3, - has_default_value=False, - default_value=[], - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=b"\310\336\037\000", - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - ], - extensions=[], - nested_types=[], - enum_types=[], - serialized_options=None, - is_extendable=False, - syntax="proto3", - extension_ranges=[], - oneofs=[], - serialized_start=320, - serialized_end=377, -) - -_VALUEOP.fields_by_name["proof"].message_type = _PROOF -_PROOFOPS.fields_by_name["ops"].message_type = _PROOFOP -DESCRIPTOR.message_types_by_name["Proof"] = _PROOF -DESCRIPTOR.message_types_by_name["ValueOp"] = _VALUEOP -DESCRIPTOR.message_types_by_name["DominoOp"] = _DOMINOOP -DESCRIPTOR.message_types_by_name["ProofOp"] = _PROOFOP -DESCRIPTOR.message_types_by_name["ProofOps"] = _PROOFOPS -_sym_db.RegisterFileDescriptor(DESCRIPTOR) - -Proof = _reflection.GeneratedProtocolMessageType( - "Proof", - (_message.Message,), - { - "DESCRIPTOR": _PROOF, - "__module__": "tendermint.crypto.proof_pb2" - # @@protoc_insertion_point(class_scope:tendermint.crypto.Proof) - }, -) -_sym_db.RegisterMessage(Proof) - -ValueOp = _reflection.GeneratedProtocolMessageType( - "ValueOp", - (_message.Message,), - { - "DESCRIPTOR": _VALUEOP, - "__module__": "tendermint.crypto.proof_pb2" - # @@protoc_insertion_point(class_scope:tendermint.crypto.ValueOp) - }, -) -_sym_db.RegisterMessage(ValueOp) - -DominoOp = _reflection.GeneratedProtocolMessageType( - "DominoOp", - (_message.Message,), - { - "DESCRIPTOR": _DOMINOOP, - "__module__": "tendermint.crypto.proof_pb2" - # @@protoc_insertion_point(class_scope:tendermint.crypto.DominoOp) - }, -) -_sym_db.RegisterMessage(DominoOp) - -ProofOp = _reflection.GeneratedProtocolMessageType( - "ProofOp", - (_message.Message,), - { - "DESCRIPTOR": _PROOFOP, - "__module__": "tendermint.crypto.proof_pb2" - # @@protoc_insertion_point(class_scope:tendermint.crypto.ProofOp) - }, -) -_sym_db.RegisterMessage(ProofOp) - -ProofOps = _reflection.GeneratedProtocolMessageType( - "ProofOps", - (_message.Message,), - { - "DESCRIPTOR": _PROOFOPS, - "__module__": "tendermint.crypto.proof_pb2" - # @@protoc_insertion_point(class_scope:tendermint.crypto.ProofOps) - }, -) -_sym_db.RegisterMessage(ProofOps) - - -DESCRIPTOR._options = None -_PROOFOPS.fields_by_name["ops"]._options = None +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile( + b'\n\x1dtendermint/crypto/proof.proto\x12\x11tendermint.crypto\x1a\x14gogoproto/gogo.proto"G\n\x05Proof\x12\r\n\x05total\x18\x01 \x01(\x03\x12\r\n\x05index\x18\x02 \x01(\x03\x12\x11\n\tleaf_hash\x18\x03 \x01(\x0c\x12\r\n\x05\x61unts\x18\x04 \x03(\x0c"?\n\x07ValueOp\x12\x0b\n\x03key\x18\x01 \x01(\x0c\x12\'\n\x05proof\x18\x02 \x01(\x0b\x32\x18.tendermint.crypto.Proof"6\n\x08\x44ominoOp\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05input\x18\x02 \x01(\t\x12\x0e\n\x06output\x18\x03 \x01(\t"2\n\x07ProofOp\x12\x0c\n\x04type\x18\x01 \x01(\t\x12\x0b\n\x03key\x18\x02 \x01(\x0c\x12\x0c\n\x04\x64\x61ta\x18\x03 \x01(\x0c"9\n\x08ProofOps\x12-\n\x03ops\x18\x01 \x03(\x0b\x32\x1a.tendermint.crypto.ProofOpB\x04\xc8\xde\x1f\x00\x42:Z8github.com/tendermint/tendermint/proto/tendermint/cryptob\x06proto3' +) + +_globals = globals() +_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) +_builder.BuildTopDescriptorsAndMessages( + DESCRIPTOR, "tendermint.crypto.proof_pb2", _globals +) +if _descriptor._USE_C_DESCRIPTORS == False: + DESCRIPTOR._options = None + DESCRIPTOR._serialized_options = ( + b"Z8github.com/tendermint/tendermint/proto/tendermint/crypto" + ) + _PROOFOPS.fields_by_name["ops"]._options = None + _PROOFOPS.fields_by_name["ops"]._serialized_options = b"\310\336\037\000" + _globals["_PROOF"]._serialized_start = 74 + _globals["_PROOF"]._serialized_end = 145 + _globals["_VALUEOP"]._serialized_start = 147 + _globals["_VALUEOP"]._serialized_end = 210 + _globals["_DOMINOOP"]._serialized_start = 212 + _globals["_DOMINOOP"]._serialized_end = 266 + _globals["_PROOFOP"]._serialized_start = 268 + _globals["_PROOFOP"]._serialized_end = 318 + _globals["_PROOFOPS"]._serialized_start = 320 + _globals["_PROOFOPS"]._serialized_end = 377 # @@protoc_insertion_point(module_scope) diff --git a/packages/valory/connections/abci/tendermint/types/params_pb2.py b/packages/valory/connections/abci/tendermint/types/params_pb2.py index 6a9d1df49c..c94e411446 100644 --- a/packages/valory/connections/abci/tendermint/types/params_pb2.py +++ b/packages/valory/connections/abci/tendermint/types/params_pb2.py @@ -3,9 +3,9 @@ # source: tendermint/types/params.proto """Generated protocol buffer code.""" from google.protobuf import descriptor as _descriptor -from google.protobuf import message as _message -from google.protobuf import reflection as _reflection +from google.protobuf import descriptor_pool as _descriptor_pool from google.protobuf import symbol_database as _symbol_database +from google.protobuf.internal import builder as _builder # @@protoc_insertion_point(imports) @@ -20,505 +20,50 @@ ) -DESCRIPTOR = _descriptor.FileDescriptor( - name="tendermint/types/params.proto", - package="tendermint.types", - syntax="proto3", - serialized_options=b"Z7github.com/tendermint/tendermint/proto/tendermint/types\250\342\036\001", - create_key=_descriptor._internal_create_key, - serialized_pb=b'\n\x1dtendermint/types/params.proto\x12\x10tendermint.types\x1a\x14gogoproto/gogo.proto\x1a\x1egoogle/protobuf/duration.proto"\xf3\x01\n\x0f\x43onsensusParams\x12\x32\n\x05\x62lock\x18\x01 \x01(\x0b\x32\x1d.tendermint.types.BlockParamsB\x04\xc8\xde\x1f\x00\x12\x38\n\x08\x65vidence\x18\x02 \x01(\x0b\x32 .tendermint.types.EvidenceParamsB\x04\xc8\xde\x1f\x00\x12:\n\tvalidator\x18\x03 \x01(\x0b\x32!.tendermint.types.ValidatorParamsB\x04\xc8\xde\x1f\x00\x12\x36\n\x07version\x18\x04 \x01(\x0b\x32\x1f.tendermint.types.VersionParamsB\x04\xc8\xde\x1f\x00"G\n\x0b\x42lockParams\x12\x11\n\tmax_bytes\x18\x01 \x01(\x03\x12\x0f\n\x07max_gas\x18\x02 \x01(\x03\x12\x14\n\x0ctime_iota_ms\x18\x03 \x01(\x03"~\n\x0e\x45videnceParams\x12\x1a\n\x12max_age_num_blocks\x18\x01 \x01(\x03\x12=\n\x10max_age_duration\x18\x02 \x01(\x0b\x32\x19.google.protobuf.DurationB\x08\xc8\xde\x1f\x00\x98\xdf\x1f\x01\x12\x11\n\tmax_bytes\x18\x03 \x01(\x03"2\n\x0fValidatorParams\x12\x15\n\rpub_key_types\x18\x01 \x03(\t:\x08\xb8\xa0\x1f\x01\xe8\xa0\x1f\x01".\n\rVersionParams\x12\x13\n\x0b\x61pp_version\x18\x01 \x01(\x04:\x08\xb8\xa0\x1f\x01\xe8\xa0\x1f\x01">\n\x0cHashedParams\x12\x17\n\x0f\x62lock_max_bytes\x18\x01 \x01(\x03\x12\x15\n\rblock_max_gas\x18\x02 \x01(\x03\x42=Z7github.com/tendermint/tendermint/proto/tendermint/types\xa8\xe2\x1e\x01\x62\x06proto3', - dependencies=[ - gogoproto_dot_gogo__pb2.DESCRIPTOR, - google_dot_protobuf_dot_duration__pb2.DESCRIPTOR, - ], +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile( + b'\n\x1dtendermint/types/params.proto\x12\x10tendermint.types\x1a\x14gogoproto/gogo.proto\x1a\x1egoogle/protobuf/duration.proto"\xf3\x01\n\x0f\x43onsensusParams\x12\x32\n\x05\x62lock\x18\x01 \x01(\x0b\x32\x1d.tendermint.types.BlockParamsB\x04\xc8\xde\x1f\x00\x12\x38\n\x08\x65vidence\x18\x02 \x01(\x0b\x32 .tendermint.types.EvidenceParamsB\x04\xc8\xde\x1f\x00\x12:\n\tvalidator\x18\x03 \x01(\x0b\x32!.tendermint.types.ValidatorParamsB\x04\xc8\xde\x1f\x00\x12\x36\n\x07version\x18\x04 \x01(\x0b\x32\x1f.tendermint.types.VersionParamsB\x04\xc8\xde\x1f\x00"G\n\x0b\x42lockParams\x12\x11\n\tmax_bytes\x18\x01 \x01(\x03\x12\x0f\n\x07max_gas\x18\x02 \x01(\x03\x12\x14\n\x0ctime_iota_ms\x18\x03 \x01(\x03"~\n\x0e\x45videnceParams\x12\x1a\n\x12max_age_num_blocks\x18\x01 \x01(\x03\x12=\n\x10max_age_duration\x18\x02 \x01(\x0b\x32\x19.google.protobuf.DurationB\x08\xc8\xde\x1f\x00\x98\xdf\x1f\x01\x12\x11\n\tmax_bytes\x18\x03 \x01(\x03"2\n\x0fValidatorParams\x12\x15\n\rpub_key_types\x18\x01 \x03(\t:\x08\xb8\xa0\x1f\x01\xe8\xa0\x1f\x01".\n\rVersionParams\x12\x13\n\x0b\x61pp_version\x18\x01 \x01(\x04:\x08\xb8\xa0\x1f\x01\xe8\xa0\x1f\x01">\n\x0cHashedParams\x12\x17\n\x0f\x62lock_max_bytes\x18\x01 \x01(\x03\x12\x15\n\rblock_max_gas\x18\x02 \x01(\x03\x42=Z7github.com/tendermint/tendermint/proto/tendermint/types\xa8\xe2\x1e\x01\x62\x06proto3' ) - -_CONSENSUSPARAMS = _descriptor.Descriptor( - name="ConsensusParams", - full_name="tendermint.types.ConsensusParams", - filename=None, - file=DESCRIPTOR, - containing_type=None, - create_key=_descriptor._internal_create_key, - fields=[ - _descriptor.FieldDescriptor( - name="block", - full_name="tendermint.types.ConsensusParams.block", - index=0, - number=1, - type=11, - cpp_type=10, - label=1, - has_default_value=False, - default_value=None, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=b"\310\336\037\000", - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="evidence", - full_name="tendermint.types.ConsensusParams.evidence", - index=1, - number=2, - type=11, - cpp_type=10, - label=1, - has_default_value=False, - default_value=None, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=b"\310\336\037\000", - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="validator", - full_name="tendermint.types.ConsensusParams.validator", - index=2, - number=3, - type=11, - cpp_type=10, - label=1, - has_default_value=False, - default_value=None, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=b"\310\336\037\000", - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="version", - full_name="tendermint.types.ConsensusParams.version", - index=3, - number=4, - type=11, - cpp_type=10, - label=1, - has_default_value=False, - default_value=None, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=b"\310\336\037\000", - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - ], - extensions=[], - nested_types=[], - enum_types=[], - serialized_options=None, - is_extendable=False, - syntax="proto3", - extension_ranges=[], - oneofs=[], - serialized_start=106, - serialized_end=349, -) - - -_BLOCKPARAMS = _descriptor.Descriptor( - name="BlockParams", - full_name="tendermint.types.BlockParams", - filename=None, - file=DESCRIPTOR, - containing_type=None, - create_key=_descriptor._internal_create_key, - fields=[ - _descriptor.FieldDescriptor( - name="max_bytes", - full_name="tendermint.types.BlockParams.max_bytes", - index=0, - number=1, - type=3, - cpp_type=2, - label=1, - has_default_value=False, - default_value=0, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="max_gas", - full_name="tendermint.types.BlockParams.max_gas", - index=1, - number=2, - type=3, - cpp_type=2, - label=1, - has_default_value=False, - default_value=0, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="time_iota_ms", - full_name="tendermint.types.BlockParams.time_iota_ms", - index=2, - number=3, - type=3, - cpp_type=2, - label=1, - has_default_value=False, - default_value=0, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - ], - extensions=[], - nested_types=[], - enum_types=[], - serialized_options=None, - is_extendable=False, - syntax="proto3", - extension_ranges=[], - oneofs=[], - serialized_start=351, - serialized_end=422, -) - - -_EVIDENCEPARAMS = _descriptor.Descriptor( - name="EvidenceParams", - full_name="tendermint.types.EvidenceParams", - filename=None, - file=DESCRIPTOR, - containing_type=None, - create_key=_descriptor._internal_create_key, - fields=[ - _descriptor.FieldDescriptor( - name="max_age_num_blocks", - full_name="tendermint.types.EvidenceParams.max_age_num_blocks", - index=0, - number=1, - type=3, - cpp_type=2, - label=1, - has_default_value=False, - default_value=0, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="max_age_duration", - full_name="tendermint.types.EvidenceParams.max_age_duration", - index=1, - number=2, - type=11, - cpp_type=10, - label=1, - has_default_value=False, - default_value=None, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=b"\310\336\037\000\230\337\037\001", - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="max_bytes", - full_name="tendermint.types.EvidenceParams.max_bytes", - index=2, - number=3, - type=3, - cpp_type=2, - label=1, - has_default_value=False, - default_value=0, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - ], - extensions=[], - nested_types=[], - enum_types=[], - serialized_options=None, - is_extendable=False, - syntax="proto3", - extension_ranges=[], - oneofs=[], - serialized_start=424, - serialized_end=550, -) - - -_VALIDATORPARAMS = _descriptor.Descriptor( - name="ValidatorParams", - full_name="tendermint.types.ValidatorParams", - filename=None, - file=DESCRIPTOR, - containing_type=None, - create_key=_descriptor._internal_create_key, - fields=[ - _descriptor.FieldDescriptor( - name="pub_key_types", - full_name="tendermint.types.ValidatorParams.pub_key_types", - index=0, - number=1, - type=9, - cpp_type=9, - label=3, - has_default_value=False, - default_value=[], - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - ], - extensions=[], - nested_types=[], - enum_types=[], - serialized_options=b"\270\240\037\001\350\240\037\001", - is_extendable=False, - syntax="proto3", - extension_ranges=[], - oneofs=[], - serialized_start=552, - serialized_end=602, -) - - -_VERSIONPARAMS = _descriptor.Descriptor( - name="VersionParams", - full_name="tendermint.types.VersionParams", - filename=None, - file=DESCRIPTOR, - containing_type=None, - create_key=_descriptor._internal_create_key, - fields=[ - _descriptor.FieldDescriptor( - name="app_version", - full_name="tendermint.types.VersionParams.app_version", - index=0, - number=1, - type=4, - cpp_type=4, - label=1, - has_default_value=False, - default_value=0, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - ], - extensions=[], - nested_types=[], - enum_types=[], - serialized_options=b"\270\240\037\001\350\240\037\001", - is_extendable=False, - syntax="proto3", - extension_ranges=[], - oneofs=[], - serialized_start=604, - serialized_end=650, -) - - -_HASHEDPARAMS = _descriptor.Descriptor( - name="HashedParams", - full_name="tendermint.types.HashedParams", - filename=None, - file=DESCRIPTOR, - containing_type=None, - create_key=_descriptor._internal_create_key, - fields=[ - _descriptor.FieldDescriptor( - name="block_max_bytes", - full_name="tendermint.types.HashedParams.block_max_bytes", - index=0, - number=1, - type=3, - cpp_type=2, - label=1, - has_default_value=False, - default_value=0, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="block_max_gas", - full_name="tendermint.types.HashedParams.block_max_gas", - index=1, - number=2, - type=3, - cpp_type=2, - label=1, - has_default_value=False, - default_value=0, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - ], - extensions=[], - nested_types=[], - enum_types=[], - serialized_options=None, - is_extendable=False, - syntax="proto3", - extension_ranges=[], - oneofs=[], - serialized_start=652, - serialized_end=714, +_globals = globals() +_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) +_builder.BuildTopDescriptorsAndMessages( + DESCRIPTOR, "tendermint.types.params_pb2", _globals ) - -_CONSENSUSPARAMS.fields_by_name["block"].message_type = _BLOCKPARAMS -_CONSENSUSPARAMS.fields_by_name["evidence"].message_type = _EVIDENCEPARAMS -_CONSENSUSPARAMS.fields_by_name["validator"].message_type = _VALIDATORPARAMS -_CONSENSUSPARAMS.fields_by_name["version"].message_type = _VERSIONPARAMS -_EVIDENCEPARAMS.fields_by_name[ - "max_age_duration" -].message_type = google_dot_protobuf_dot_duration__pb2._DURATION -DESCRIPTOR.message_types_by_name["ConsensusParams"] = _CONSENSUSPARAMS -DESCRIPTOR.message_types_by_name["BlockParams"] = _BLOCKPARAMS -DESCRIPTOR.message_types_by_name["EvidenceParams"] = _EVIDENCEPARAMS -DESCRIPTOR.message_types_by_name["ValidatorParams"] = _VALIDATORPARAMS -DESCRIPTOR.message_types_by_name["VersionParams"] = _VERSIONPARAMS -DESCRIPTOR.message_types_by_name["HashedParams"] = _HASHEDPARAMS -_sym_db.RegisterFileDescriptor(DESCRIPTOR) - -ConsensusParams = _reflection.GeneratedProtocolMessageType( - "ConsensusParams", - (_message.Message,), - { - "DESCRIPTOR": _CONSENSUSPARAMS, - "__module__": "tendermint.types.params_pb2" - # @@protoc_insertion_point(class_scope:tendermint.types.ConsensusParams) - }, -) -_sym_db.RegisterMessage(ConsensusParams) - -BlockParams = _reflection.GeneratedProtocolMessageType( - "BlockParams", - (_message.Message,), - { - "DESCRIPTOR": _BLOCKPARAMS, - "__module__": "tendermint.types.params_pb2" - # @@protoc_insertion_point(class_scope:tendermint.types.BlockParams) - }, -) -_sym_db.RegisterMessage(BlockParams) - -EvidenceParams = _reflection.GeneratedProtocolMessageType( - "EvidenceParams", - (_message.Message,), - { - "DESCRIPTOR": _EVIDENCEPARAMS, - "__module__": "tendermint.types.params_pb2" - # @@protoc_insertion_point(class_scope:tendermint.types.EvidenceParams) - }, -) -_sym_db.RegisterMessage(EvidenceParams) - -ValidatorParams = _reflection.GeneratedProtocolMessageType( - "ValidatorParams", - (_message.Message,), - { - "DESCRIPTOR": _VALIDATORPARAMS, - "__module__": "tendermint.types.params_pb2" - # @@protoc_insertion_point(class_scope:tendermint.types.ValidatorParams) - }, -) -_sym_db.RegisterMessage(ValidatorParams) - -VersionParams = _reflection.GeneratedProtocolMessageType( - "VersionParams", - (_message.Message,), - { - "DESCRIPTOR": _VERSIONPARAMS, - "__module__": "tendermint.types.params_pb2" - # @@protoc_insertion_point(class_scope:tendermint.types.VersionParams) - }, -) -_sym_db.RegisterMessage(VersionParams) - -HashedParams = _reflection.GeneratedProtocolMessageType( - "HashedParams", - (_message.Message,), - { - "DESCRIPTOR": _HASHEDPARAMS, - "__module__": "tendermint.types.params_pb2" - # @@protoc_insertion_point(class_scope:tendermint.types.HashedParams) - }, -) -_sym_db.RegisterMessage(HashedParams) - - -DESCRIPTOR._options = None -_CONSENSUSPARAMS.fields_by_name["block"]._options = None -_CONSENSUSPARAMS.fields_by_name["evidence"]._options = None -_CONSENSUSPARAMS.fields_by_name["validator"]._options = None -_CONSENSUSPARAMS.fields_by_name["version"]._options = None -_EVIDENCEPARAMS.fields_by_name["max_age_duration"]._options = None -_VALIDATORPARAMS._options = None -_VERSIONPARAMS._options = None +if _descriptor._USE_C_DESCRIPTORS == False: + DESCRIPTOR._options = None + DESCRIPTOR._serialized_options = ( + b"Z7github.com/tendermint/tendermint/proto/tendermint/types\250\342\036\001" + ) + _CONSENSUSPARAMS.fields_by_name["block"]._options = None + _CONSENSUSPARAMS.fields_by_name["block"]._serialized_options = b"\310\336\037\000" + _CONSENSUSPARAMS.fields_by_name["evidence"]._options = None + _CONSENSUSPARAMS.fields_by_name[ + "evidence" + ]._serialized_options = b"\310\336\037\000" + _CONSENSUSPARAMS.fields_by_name["validator"]._options = None + _CONSENSUSPARAMS.fields_by_name[ + "validator" + ]._serialized_options = b"\310\336\037\000" + _CONSENSUSPARAMS.fields_by_name["version"]._options = None + _CONSENSUSPARAMS.fields_by_name["version"]._serialized_options = b"\310\336\037\000" + _EVIDENCEPARAMS.fields_by_name["max_age_duration"]._options = None + _EVIDENCEPARAMS.fields_by_name[ + "max_age_duration" + ]._serialized_options = b"\310\336\037\000\230\337\037\001" + _VALIDATORPARAMS._options = None + _VALIDATORPARAMS._serialized_options = b"\270\240\037\001\350\240\037\001" + _VERSIONPARAMS._options = None + _VERSIONPARAMS._serialized_options = b"\270\240\037\001\350\240\037\001" + _globals["_CONSENSUSPARAMS"]._serialized_start = 106 + _globals["_CONSENSUSPARAMS"]._serialized_end = 349 + _globals["_BLOCKPARAMS"]._serialized_start = 351 + _globals["_BLOCKPARAMS"]._serialized_end = 422 + _globals["_EVIDENCEPARAMS"]._serialized_start = 424 + _globals["_EVIDENCEPARAMS"]._serialized_end = 550 + _globals["_VALIDATORPARAMS"]._serialized_start = 552 + _globals["_VALIDATORPARAMS"]._serialized_end = 602 + _globals["_VERSIONPARAMS"]._serialized_start = 604 + _globals["_VERSIONPARAMS"]._serialized_end = 650 + _globals["_HASHEDPARAMS"]._serialized_start = 652 + _globals["_HASHEDPARAMS"]._serialized_end = 714 # @@protoc_insertion_point(module_scope) diff --git a/packages/valory/connections/abci/tendermint/types/types_pb2.py b/packages/valory/connections/abci/tendermint/types/types_pb2.py index f9a0da590e..1818466ed0 100644 --- a/packages/valory/connections/abci/tendermint/types/types_pb2.py +++ b/packages/valory/connections/abci/tendermint/types/types_pb2.py @@ -3,10 +3,9 @@ # source: tendermint/types/types.proto """Generated protocol buffer code.""" from google.protobuf import descriptor as _descriptor -from google.protobuf import message as _message -from google.protobuf import reflection as _reflection +from google.protobuf import descriptor_pool as _descriptor_pool from google.protobuf import symbol_database as _symbol_database -from google.protobuf.internal import enum_type_wrapper +from google.protobuf.internal import builder as _builder # @@protoc_insertion_point(imports) @@ -30,1698 +29,130 @@ ) -DESCRIPTOR = _descriptor.FileDescriptor( - name="tendermint/types/types.proto", - package="tendermint.types", - syntax="proto3", - serialized_options=b"Z7github.com/tendermint/tendermint/proto/tendermint/types", - create_key=_descriptor._internal_create_key, - serialized_pb=b'\n\x1ctendermint/types/types.proto\x12\x10tendermint.types\x1a\x14gogoproto/gogo.proto\x1a\x1fgoogle/protobuf/timestamp.proto\x1a\x1dtendermint/crypto/proof.proto\x1a\x1etendermint/version/types.proto\x1a tendermint/types/validator.proto",\n\rPartSetHeader\x12\r\n\x05total\x18\x01 \x01(\r\x12\x0c\n\x04hash\x18\x02 \x01(\x0c"S\n\x04Part\x12\r\n\x05index\x18\x01 \x01(\r\x12\r\n\x05\x62ytes\x18\x02 \x01(\x0c\x12-\n\x05proof\x18\x03 \x01(\x0b\x32\x18.tendermint.crypto.ProofB\x04\xc8\xde\x1f\x00"W\n\x07\x42lockID\x12\x0c\n\x04hash\x18\x01 \x01(\x0c\x12>\n\x0fpart_set_header\x18\x02 \x01(\x0b\x32\x1f.tendermint.types.PartSetHeaderB\x04\xc8\xde\x1f\x00"\xb3\x03\n\x06Header\x12\x34\n\x07version\x18\x01 \x01(\x0b\x32\x1d.tendermint.version.ConsensusB\x04\xc8\xde\x1f\x00\x12\x1d\n\x08\x63hain_id\x18\x02 \x01(\tB\x0b\xe2\xde\x1f\x07\x43hainID\x12\x0e\n\x06height\x18\x03 \x01(\x03\x12\x32\n\x04time\x18\x04 \x01(\x0b\x32\x1a.google.protobuf.TimestampB\x08\xc8\xde\x1f\x00\x90\xdf\x1f\x01\x12\x36\n\rlast_block_id\x18\x05 \x01(\x0b\x32\x19.tendermint.types.BlockIDB\x04\xc8\xde\x1f\x00\x12\x18\n\x10last_commit_hash\x18\x06 \x01(\x0c\x12\x11\n\tdata_hash\x18\x07 \x01(\x0c\x12\x17\n\x0fvalidators_hash\x18\x08 \x01(\x0c\x12\x1c\n\x14next_validators_hash\x18\t \x01(\x0c\x12\x16\n\x0e\x63onsensus_hash\x18\n \x01(\x0c\x12\x10\n\x08\x61pp_hash\x18\x0b \x01(\x0c\x12\x19\n\x11last_results_hash\x18\x0c \x01(\x0c\x12\x15\n\revidence_hash\x18\r \x01(\x0c\x12\x18\n\x10proposer_address\x18\x0e \x01(\x0c"\x13\n\x04\x44\x61ta\x12\x0b\n\x03txs\x18\x01 \x03(\x0c"\x92\x02\n\x04Vote\x12-\n\x04type\x18\x01 \x01(\x0e\x32\x1f.tendermint.types.SignedMsgType\x12\x0e\n\x06height\x18\x02 \x01(\x03\x12\r\n\x05round\x18\x03 \x01(\x05\x12<\n\x08\x62lock_id\x18\x04 \x01(\x0b\x32\x19.tendermint.types.BlockIDB\x0f\xc8\xde\x1f\x00\xe2\xde\x1f\x07\x42lockID\x12\x37\n\ttimestamp\x18\x05 \x01(\x0b\x32\x1a.google.protobuf.TimestampB\x08\xc8\xde\x1f\x00\x90\xdf\x1f\x01\x12\x19\n\x11validator_address\x18\x06 \x01(\x0c\x12\x17\n\x0fvalidator_index\x18\x07 \x01(\x05\x12\x11\n\tsignature\x18\x08 \x01(\x0c"\x9c\x01\n\x06\x43ommit\x12\x0e\n\x06height\x18\x01 \x01(\x03\x12\r\n\x05round\x18\x02 \x01(\x05\x12<\n\x08\x62lock_id\x18\x03 \x01(\x0b\x32\x19.tendermint.types.BlockIDB\x0f\xc8\xde\x1f\x00\xe2\xde\x1f\x07\x42lockID\x12\x35\n\nsignatures\x18\x04 \x03(\x0b\x32\x1b.tendermint.types.CommitSigB\x04\xc8\xde\x1f\x00"\xa8\x01\n\tCommitSig\x12\x34\n\rblock_id_flag\x18\x01 \x01(\x0e\x32\x1d.tendermint.types.BlockIDFlag\x12\x19\n\x11validator_address\x18\x02 \x01(\x0c\x12\x37\n\ttimestamp\x18\x03 \x01(\x0b\x32\x1a.google.protobuf.TimestampB\x08\xc8\xde\x1f\x00\x90\xdf\x1f\x01\x12\x11\n\tsignature\x18\x04 \x01(\x0c"\xf5\x01\n\x08Proposal\x12-\n\x04type\x18\x01 \x01(\x0e\x32\x1f.tendermint.types.SignedMsgType\x12\x0e\n\x06height\x18\x02 \x01(\x03\x12\r\n\x05round\x18\x03 \x01(\x05\x12\x11\n\tpol_round\x18\x04 \x01(\x05\x12<\n\x08\x62lock_id\x18\x05 \x01(\x0b\x32\x19.tendermint.types.BlockIDB\x0f\xe2\xde\x1f\x07\x42lockID\xc8\xde\x1f\x00\x12\x37\n\ttimestamp\x18\x06 \x01(\x0b\x32\x1a.google.protobuf.TimestampB\x08\xc8\xde\x1f\x00\x90\xdf\x1f\x01\x12\x11\n\tsignature\x18\x07 \x01(\x0c"b\n\x0cSignedHeader\x12(\n\x06header\x18\x01 \x01(\x0b\x32\x18.tendermint.types.Header\x12(\n\x06\x63ommit\x18\x02 \x01(\x0b\x32\x18.tendermint.types.Commit"z\n\nLightBlock\x12\x35\n\rsigned_header\x18\x01 \x01(\x0b\x32\x1e.tendermint.types.SignedHeader\x12\x35\n\rvalidator_set\x18\x02 \x01(\x0b\x32\x1e.tendermint.types.ValidatorSet"\x9e\x01\n\tBlockMeta\x12<\n\x08\x62lock_id\x18\x01 \x01(\x0b\x32\x19.tendermint.types.BlockIDB\x0f\xe2\xde\x1f\x07\x42lockID\xc8\xde\x1f\x00\x12\x12\n\nblock_size\x18\x02 \x01(\x03\x12.\n\x06header\x18\x03 \x01(\x0b\x32\x18.tendermint.types.HeaderB\x04\xc8\xde\x1f\x00\x12\x0f\n\x07num_txs\x18\x04 \x01(\x03"S\n\x07TxProof\x12\x11\n\troot_hash\x18\x01 \x01(\x0c\x12\x0c\n\x04\x64\x61ta\x18\x02 \x01(\x0c\x12\'\n\x05proof\x18\x03 \x01(\x0b\x32\x18.tendermint.crypto.Proof*\xd7\x01\n\x0b\x42lockIDFlag\x12\x31\n\x15\x42LOCK_ID_FLAG_UNKNOWN\x10\x00\x1a\x16\x8a\x9d \x12\x42lockIDFlagUnknown\x12/\n\x14\x42LOCK_ID_FLAG_ABSENT\x10\x01\x1a\x15\x8a\x9d \x11\x42lockIDFlagAbsent\x12/\n\x14\x42LOCK_ID_FLAG_COMMIT\x10\x02\x1a\x15\x8a\x9d \x11\x42lockIDFlagCommit\x12)\n\x11\x42LOCK_ID_FLAG_NIL\x10\x03\x1a\x12\x8a\x9d \x0e\x42lockIDFlagNil\x1a\x08\xa8\xa4\x1e\x01\x88\xa3\x1e\x00*\xd7\x01\n\rSignedMsgType\x12,\n\x17SIGNED_MSG_TYPE_UNKNOWN\x10\x00\x1a\x0f\x8a\x9d \x0bUnknownType\x12,\n\x17SIGNED_MSG_TYPE_PREVOTE\x10\x01\x1a\x0f\x8a\x9d \x0bPrevoteType\x12\x30\n\x19SIGNED_MSG_TYPE_PRECOMMIT\x10\x02\x1a\x11\x8a\x9d \rPrecommitType\x12.\n\x18SIGNED_MSG_TYPE_PROPOSAL\x10 \x1a\x10\x8a\x9d \x0cProposalType\x1a\x08\xa8\xa4\x1e\x01\x88\xa3\x1e\x00\x42\x39Z7github.com/tendermint/tendermint/proto/tendermint/typesb\x06proto3', - dependencies=[ - gogoproto_dot_gogo__pb2.DESCRIPTOR, - google_dot_protobuf_dot_timestamp__pb2.DESCRIPTOR, - tendermint_dot_crypto_dot_proof__pb2.DESCRIPTOR, - tendermint_dot_version_dot_types__pb2.DESCRIPTOR, - tendermint_dot_types_dot_validator__pb2.DESCRIPTOR, - ], -) - -_BLOCKIDFLAG = _descriptor.EnumDescriptor( - name="BlockIDFlag", - full_name="tendermint.types.BlockIDFlag", - filename=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - values=[ - _descriptor.EnumValueDescriptor( - name="BLOCK_ID_FLAG_UNKNOWN", - index=0, - number=0, - serialized_options=b"\212\235 \022BlockIDFlagUnknown", - type=None, - create_key=_descriptor._internal_create_key, - ), - _descriptor.EnumValueDescriptor( - name="BLOCK_ID_FLAG_ABSENT", - index=1, - number=1, - serialized_options=b"\212\235 \021BlockIDFlagAbsent", - type=None, - create_key=_descriptor._internal_create_key, - ), - _descriptor.EnumValueDescriptor( - name="BLOCK_ID_FLAG_COMMIT", - index=2, - number=2, - serialized_options=b"\212\235 \021BlockIDFlagCommit", - type=None, - create_key=_descriptor._internal_create_key, - ), - _descriptor.EnumValueDescriptor( - name="BLOCK_ID_FLAG_NIL", - index=3, - number=3, - serialized_options=b"\212\235 \016BlockIDFlagNil", - type=None, - create_key=_descriptor._internal_create_key, - ), - ], - containing_type=None, - serialized_options=b"\250\244\036\001\210\243\036\000", - serialized_start=2207, - serialized_end=2422, -) -_sym_db.RegisterEnumDescriptor(_BLOCKIDFLAG) - -BlockIDFlag = enum_type_wrapper.EnumTypeWrapper(_BLOCKIDFLAG) -_SIGNEDMSGTYPE = _descriptor.EnumDescriptor( - name="SignedMsgType", - full_name="tendermint.types.SignedMsgType", - filename=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - values=[ - _descriptor.EnumValueDescriptor( - name="SIGNED_MSG_TYPE_UNKNOWN", - index=0, - number=0, - serialized_options=b"\212\235 \013UnknownType", - type=None, - create_key=_descriptor._internal_create_key, - ), - _descriptor.EnumValueDescriptor( - name="SIGNED_MSG_TYPE_PREVOTE", - index=1, - number=1, - serialized_options=b"\212\235 \013PrevoteType", - type=None, - create_key=_descriptor._internal_create_key, - ), - _descriptor.EnumValueDescriptor( - name="SIGNED_MSG_TYPE_PRECOMMIT", - index=2, - number=2, - serialized_options=b"\212\235 \rPrecommitType", - type=None, - create_key=_descriptor._internal_create_key, - ), - _descriptor.EnumValueDescriptor( - name="SIGNED_MSG_TYPE_PROPOSAL", - index=3, - number=32, - serialized_options=b"\212\235 \014ProposalType", - type=None, - create_key=_descriptor._internal_create_key, - ), - ], - containing_type=None, - serialized_options=b"\250\244\036\001\210\243\036\000", - serialized_start=2425, - serialized_end=2640, -) -_sym_db.RegisterEnumDescriptor(_SIGNEDMSGTYPE) - -SignedMsgType = enum_type_wrapper.EnumTypeWrapper(_SIGNEDMSGTYPE) -BLOCK_ID_FLAG_UNKNOWN = 0 -BLOCK_ID_FLAG_ABSENT = 1 -BLOCK_ID_FLAG_COMMIT = 2 -BLOCK_ID_FLAG_NIL = 3 -SIGNED_MSG_TYPE_UNKNOWN = 0 -SIGNED_MSG_TYPE_PREVOTE = 1 -SIGNED_MSG_TYPE_PRECOMMIT = 2 -SIGNED_MSG_TYPE_PROPOSAL = 32 - - -_PARTSETHEADER = _descriptor.Descriptor( - name="PartSetHeader", - full_name="tendermint.types.PartSetHeader", - filename=None, - file=DESCRIPTOR, - containing_type=None, - create_key=_descriptor._internal_create_key, - fields=[ - _descriptor.FieldDescriptor( - name="total", - full_name="tendermint.types.PartSetHeader.total", - index=0, - number=1, - type=13, - cpp_type=3, - label=1, - has_default_value=False, - default_value=0, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="hash", - full_name="tendermint.types.PartSetHeader.hash", - index=1, - number=2, - type=12, - cpp_type=9, - label=1, - has_default_value=False, - default_value=b"", - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - ], - extensions=[], - nested_types=[], - enum_types=[], - serialized_options=None, - is_extendable=False, - syntax="proto3", - extension_ranges=[], - oneofs=[], - serialized_start=202, - serialized_end=246, -) - - -_PART = _descriptor.Descriptor( - name="Part", - full_name="tendermint.types.Part", - filename=None, - file=DESCRIPTOR, - containing_type=None, - create_key=_descriptor._internal_create_key, - fields=[ - _descriptor.FieldDescriptor( - name="index", - full_name="tendermint.types.Part.index", - index=0, - number=1, - type=13, - cpp_type=3, - label=1, - has_default_value=False, - default_value=0, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="bytes", - full_name="tendermint.types.Part.bytes", - index=1, - number=2, - type=12, - cpp_type=9, - label=1, - has_default_value=False, - default_value=b"", - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="proof", - full_name="tendermint.types.Part.proof", - index=2, - number=3, - type=11, - cpp_type=10, - label=1, - has_default_value=False, - default_value=None, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=b"\310\336\037\000", - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - ], - extensions=[], - nested_types=[], - enum_types=[], - serialized_options=None, - is_extendable=False, - syntax="proto3", - extension_ranges=[], - oneofs=[], - serialized_start=248, - serialized_end=331, -) - - -_BLOCKID = _descriptor.Descriptor( - name="BlockID", - full_name="tendermint.types.BlockID", - filename=None, - file=DESCRIPTOR, - containing_type=None, - create_key=_descriptor._internal_create_key, - fields=[ - _descriptor.FieldDescriptor( - name="hash", - full_name="tendermint.types.BlockID.hash", - index=0, - number=1, - type=12, - cpp_type=9, - label=1, - has_default_value=False, - default_value=b"", - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="part_set_header", - full_name="tendermint.types.BlockID.part_set_header", - index=1, - number=2, - type=11, - cpp_type=10, - label=1, - has_default_value=False, - default_value=None, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=b"\310\336\037\000", - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - ], - extensions=[], - nested_types=[], - enum_types=[], - serialized_options=None, - is_extendable=False, - syntax="proto3", - extension_ranges=[], - oneofs=[], - serialized_start=333, - serialized_end=420, -) - - -_HEADER = _descriptor.Descriptor( - name="Header", - full_name="tendermint.types.Header", - filename=None, - file=DESCRIPTOR, - containing_type=None, - create_key=_descriptor._internal_create_key, - fields=[ - _descriptor.FieldDescriptor( - name="version", - full_name="tendermint.types.Header.version", - index=0, - number=1, - type=11, - cpp_type=10, - label=1, - has_default_value=False, - default_value=None, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=b"\310\336\037\000", - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="chain_id", - full_name="tendermint.types.Header.chain_id", - index=1, - number=2, - type=9, - cpp_type=9, - label=1, - has_default_value=False, - default_value=b"".decode("utf-8"), - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=b"\342\336\037\007ChainID", - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="height", - full_name="tendermint.types.Header.height", - index=2, - number=3, - type=3, - cpp_type=2, - label=1, - has_default_value=False, - default_value=0, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="time", - full_name="tendermint.types.Header.time", - index=3, - number=4, - type=11, - cpp_type=10, - label=1, - has_default_value=False, - default_value=None, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=b"\310\336\037\000\220\337\037\001", - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="last_block_id", - full_name="tendermint.types.Header.last_block_id", - index=4, - number=5, - type=11, - cpp_type=10, - label=1, - has_default_value=False, - default_value=None, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=b"\310\336\037\000", - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="last_commit_hash", - full_name="tendermint.types.Header.last_commit_hash", - index=5, - number=6, - type=12, - cpp_type=9, - label=1, - has_default_value=False, - default_value=b"", - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="data_hash", - full_name="tendermint.types.Header.data_hash", - index=6, - number=7, - type=12, - cpp_type=9, - label=1, - has_default_value=False, - default_value=b"", - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="validators_hash", - full_name="tendermint.types.Header.validators_hash", - index=7, - number=8, - type=12, - cpp_type=9, - label=1, - has_default_value=False, - default_value=b"", - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="next_validators_hash", - full_name="tendermint.types.Header.next_validators_hash", - index=8, - number=9, - type=12, - cpp_type=9, - label=1, - has_default_value=False, - default_value=b"", - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="consensus_hash", - full_name="tendermint.types.Header.consensus_hash", - index=9, - number=10, - type=12, - cpp_type=9, - label=1, - has_default_value=False, - default_value=b"", - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="app_hash", - full_name="tendermint.types.Header.app_hash", - index=10, - number=11, - type=12, - cpp_type=9, - label=1, - has_default_value=False, - default_value=b"", - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="last_results_hash", - full_name="tendermint.types.Header.last_results_hash", - index=11, - number=12, - type=12, - cpp_type=9, - label=1, - has_default_value=False, - default_value=b"", - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="evidence_hash", - full_name="tendermint.types.Header.evidence_hash", - index=12, - number=13, - type=12, - cpp_type=9, - label=1, - has_default_value=False, - default_value=b"", - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="proposer_address", - full_name="tendermint.types.Header.proposer_address", - index=13, - number=14, - type=12, - cpp_type=9, - label=1, - has_default_value=False, - default_value=b"", - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - ], - extensions=[], - nested_types=[], - enum_types=[], - serialized_options=None, - is_extendable=False, - syntax="proto3", - extension_ranges=[], - oneofs=[], - serialized_start=423, - serialized_end=858, -) - - -_DATA = _descriptor.Descriptor( - name="Data", - full_name="tendermint.types.Data", - filename=None, - file=DESCRIPTOR, - containing_type=None, - create_key=_descriptor._internal_create_key, - fields=[ - _descriptor.FieldDescriptor( - name="txs", - full_name="tendermint.types.Data.txs", - index=0, - number=1, - type=12, - cpp_type=9, - label=3, - has_default_value=False, - default_value=[], - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - ], - extensions=[], - nested_types=[], - enum_types=[], - serialized_options=None, - is_extendable=False, - syntax="proto3", - extension_ranges=[], - oneofs=[], - serialized_start=860, - serialized_end=879, -) - - -_VOTE = _descriptor.Descriptor( - name="Vote", - full_name="tendermint.types.Vote", - filename=None, - file=DESCRIPTOR, - containing_type=None, - create_key=_descriptor._internal_create_key, - fields=[ - _descriptor.FieldDescriptor( - name="type", - full_name="tendermint.types.Vote.type", - index=0, - number=1, - type=14, - cpp_type=8, - label=1, - has_default_value=False, - default_value=0, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="height", - full_name="tendermint.types.Vote.height", - index=1, - number=2, - type=3, - cpp_type=2, - label=1, - has_default_value=False, - default_value=0, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="round", - full_name="tendermint.types.Vote.round", - index=2, - number=3, - type=5, - cpp_type=1, - label=1, - has_default_value=False, - default_value=0, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="block_id", - full_name="tendermint.types.Vote.block_id", - index=3, - number=4, - type=11, - cpp_type=10, - label=1, - has_default_value=False, - default_value=None, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=b"\310\336\037\000\342\336\037\007BlockID", - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="timestamp", - full_name="tendermint.types.Vote.timestamp", - index=4, - number=5, - type=11, - cpp_type=10, - label=1, - has_default_value=False, - default_value=None, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=b"\310\336\037\000\220\337\037\001", - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="validator_address", - full_name="tendermint.types.Vote.validator_address", - index=5, - number=6, - type=12, - cpp_type=9, - label=1, - has_default_value=False, - default_value=b"", - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="validator_index", - full_name="tendermint.types.Vote.validator_index", - index=6, - number=7, - type=5, - cpp_type=1, - label=1, - has_default_value=False, - default_value=0, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="signature", - full_name="tendermint.types.Vote.signature", - index=7, - number=8, - type=12, - cpp_type=9, - label=1, - has_default_value=False, - default_value=b"", - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - ], - extensions=[], - nested_types=[], - enum_types=[], - serialized_options=None, - is_extendable=False, - syntax="proto3", - extension_ranges=[], - oneofs=[], - serialized_start=882, - serialized_end=1156, -) - - -_COMMIT = _descriptor.Descriptor( - name="Commit", - full_name="tendermint.types.Commit", - filename=None, - file=DESCRIPTOR, - containing_type=None, - create_key=_descriptor._internal_create_key, - fields=[ - _descriptor.FieldDescriptor( - name="height", - full_name="tendermint.types.Commit.height", - index=0, - number=1, - type=3, - cpp_type=2, - label=1, - has_default_value=False, - default_value=0, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="round", - full_name="tendermint.types.Commit.round", - index=1, - number=2, - type=5, - cpp_type=1, - label=1, - has_default_value=False, - default_value=0, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="block_id", - full_name="tendermint.types.Commit.block_id", - index=2, - number=3, - type=11, - cpp_type=10, - label=1, - has_default_value=False, - default_value=None, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=b"\310\336\037\000\342\336\037\007BlockID", - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="signatures", - full_name="tendermint.types.Commit.signatures", - index=3, - number=4, - type=11, - cpp_type=10, - label=3, - has_default_value=False, - default_value=[], - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=b"\310\336\037\000", - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - ], - extensions=[], - nested_types=[], - enum_types=[], - serialized_options=None, - is_extendable=False, - syntax="proto3", - extension_ranges=[], - oneofs=[], - serialized_start=1159, - serialized_end=1315, -) - - -_COMMITSIG = _descriptor.Descriptor( - name="CommitSig", - full_name="tendermint.types.CommitSig", - filename=None, - file=DESCRIPTOR, - containing_type=None, - create_key=_descriptor._internal_create_key, - fields=[ - _descriptor.FieldDescriptor( - name="block_id_flag", - full_name="tendermint.types.CommitSig.block_id_flag", - index=0, - number=1, - type=14, - cpp_type=8, - label=1, - has_default_value=False, - default_value=0, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="validator_address", - full_name="tendermint.types.CommitSig.validator_address", - index=1, - number=2, - type=12, - cpp_type=9, - label=1, - has_default_value=False, - default_value=b"", - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="timestamp", - full_name="tendermint.types.CommitSig.timestamp", - index=2, - number=3, - type=11, - cpp_type=10, - label=1, - has_default_value=False, - default_value=None, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=b"\310\336\037\000\220\337\037\001", - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="signature", - full_name="tendermint.types.CommitSig.signature", - index=3, - number=4, - type=12, - cpp_type=9, - label=1, - has_default_value=False, - default_value=b"", - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - ], - extensions=[], - nested_types=[], - enum_types=[], - serialized_options=None, - is_extendable=False, - syntax="proto3", - extension_ranges=[], - oneofs=[], - serialized_start=1318, - serialized_end=1486, -) - - -_PROPOSAL = _descriptor.Descriptor( - name="Proposal", - full_name="tendermint.types.Proposal", - filename=None, - file=DESCRIPTOR, - containing_type=None, - create_key=_descriptor._internal_create_key, - fields=[ - _descriptor.FieldDescriptor( - name="type", - full_name="tendermint.types.Proposal.type", - index=0, - number=1, - type=14, - cpp_type=8, - label=1, - has_default_value=False, - default_value=0, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="height", - full_name="tendermint.types.Proposal.height", - index=1, - number=2, - type=3, - cpp_type=2, - label=1, - has_default_value=False, - default_value=0, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="round", - full_name="tendermint.types.Proposal.round", - index=2, - number=3, - type=5, - cpp_type=1, - label=1, - has_default_value=False, - default_value=0, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="pol_round", - full_name="tendermint.types.Proposal.pol_round", - index=3, - number=4, - type=5, - cpp_type=1, - label=1, - has_default_value=False, - default_value=0, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="block_id", - full_name="tendermint.types.Proposal.block_id", - index=4, - number=5, - type=11, - cpp_type=10, - label=1, - has_default_value=False, - default_value=None, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=b"\342\336\037\007BlockID\310\336\037\000", - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="timestamp", - full_name="tendermint.types.Proposal.timestamp", - index=5, - number=6, - type=11, - cpp_type=10, - label=1, - has_default_value=False, - default_value=None, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=b"\310\336\037\000\220\337\037\001", - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="signature", - full_name="tendermint.types.Proposal.signature", - index=6, - number=7, - type=12, - cpp_type=9, - label=1, - has_default_value=False, - default_value=b"", - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - ], - extensions=[], - nested_types=[], - enum_types=[], - serialized_options=None, - is_extendable=False, - syntax="proto3", - extension_ranges=[], - oneofs=[], - serialized_start=1489, - serialized_end=1734, -) - - -_SIGNEDHEADER = _descriptor.Descriptor( - name="SignedHeader", - full_name="tendermint.types.SignedHeader", - filename=None, - file=DESCRIPTOR, - containing_type=None, - create_key=_descriptor._internal_create_key, - fields=[ - _descriptor.FieldDescriptor( - name="header", - full_name="tendermint.types.SignedHeader.header", - index=0, - number=1, - type=11, - cpp_type=10, - label=1, - has_default_value=False, - default_value=None, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="commit", - full_name="tendermint.types.SignedHeader.commit", - index=1, - number=2, - type=11, - cpp_type=10, - label=1, - has_default_value=False, - default_value=None, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - ], - extensions=[], - nested_types=[], - enum_types=[], - serialized_options=None, - is_extendable=False, - syntax="proto3", - extension_ranges=[], - oneofs=[], - serialized_start=1736, - serialized_end=1834, -) - - -_LIGHTBLOCK = _descriptor.Descriptor( - name="LightBlock", - full_name="tendermint.types.LightBlock", - filename=None, - file=DESCRIPTOR, - containing_type=None, - create_key=_descriptor._internal_create_key, - fields=[ - _descriptor.FieldDescriptor( - name="signed_header", - full_name="tendermint.types.LightBlock.signed_header", - index=0, - number=1, - type=11, - cpp_type=10, - label=1, - has_default_value=False, - default_value=None, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="validator_set", - full_name="tendermint.types.LightBlock.validator_set", - index=1, - number=2, - type=11, - cpp_type=10, - label=1, - has_default_value=False, - default_value=None, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - ], - extensions=[], - nested_types=[], - enum_types=[], - serialized_options=None, - is_extendable=False, - syntax="proto3", - extension_ranges=[], - oneofs=[], - serialized_start=1836, - serialized_end=1958, -) - - -_BLOCKMETA = _descriptor.Descriptor( - name="BlockMeta", - full_name="tendermint.types.BlockMeta", - filename=None, - file=DESCRIPTOR, - containing_type=None, - create_key=_descriptor._internal_create_key, - fields=[ - _descriptor.FieldDescriptor( - name="block_id", - full_name="tendermint.types.BlockMeta.block_id", - index=0, - number=1, - type=11, - cpp_type=10, - label=1, - has_default_value=False, - default_value=None, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=b"\342\336\037\007BlockID\310\336\037\000", - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="block_size", - full_name="tendermint.types.BlockMeta.block_size", - index=1, - number=2, - type=3, - cpp_type=2, - label=1, - has_default_value=False, - default_value=0, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="header", - full_name="tendermint.types.BlockMeta.header", - index=2, - number=3, - type=11, - cpp_type=10, - label=1, - has_default_value=False, - default_value=None, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=b"\310\336\037\000", - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="num_txs", - full_name="tendermint.types.BlockMeta.num_txs", - index=3, - number=4, - type=3, - cpp_type=2, - label=1, - has_default_value=False, - default_value=0, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - ], - extensions=[], - nested_types=[], - enum_types=[], - serialized_options=None, - is_extendable=False, - syntax="proto3", - extension_ranges=[], - oneofs=[], - serialized_start=1961, - serialized_end=2119, -) - - -_TXPROOF = _descriptor.Descriptor( - name="TxProof", - full_name="tendermint.types.TxProof", - filename=None, - file=DESCRIPTOR, - containing_type=None, - create_key=_descriptor._internal_create_key, - fields=[ - _descriptor.FieldDescriptor( - name="root_hash", - full_name="tendermint.types.TxProof.root_hash", - index=0, - number=1, - type=12, - cpp_type=9, - label=1, - has_default_value=False, - default_value=b"", - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="data", - full_name="tendermint.types.TxProof.data", - index=1, - number=2, - type=12, - cpp_type=9, - label=1, - has_default_value=False, - default_value=b"", - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="proof", - full_name="tendermint.types.TxProof.proof", - index=2, - number=3, - type=11, - cpp_type=10, - label=1, - has_default_value=False, - default_value=None, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - ], - extensions=[], - nested_types=[], - enum_types=[], - serialized_options=None, - is_extendable=False, - syntax="proto3", - extension_ranges=[], - oneofs=[], - serialized_start=2121, - serialized_end=2204, -) - -_PART.fields_by_name["proof"].message_type = tendermint_dot_crypto_dot_proof__pb2._PROOF -_BLOCKID.fields_by_name["part_set_header"].message_type = _PARTSETHEADER -_HEADER.fields_by_name[ - "version" -].message_type = tendermint_dot_version_dot_types__pb2._CONSENSUS -_HEADER.fields_by_name[ - "time" -].message_type = google_dot_protobuf_dot_timestamp__pb2._TIMESTAMP -_HEADER.fields_by_name["last_block_id"].message_type = _BLOCKID -_VOTE.fields_by_name["type"].enum_type = _SIGNEDMSGTYPE -_VOTE.fields_by_name["block_id"].message_type = _BLOCKID -_VOTE.fields_by_name[ - "timestamp" -].message_type = google_dot_protobuf_dot_timestamp__pb2._TIMESTAMP -_COMMIT.fields_by_name["block_id"].message_type = _BLOCKID -_COMMIT.fields_by_name["signatures"].message_type = _COMMITSIG -_COMMITSIG.fields_by_name["block_id_flag"].enum_type = _BLOCKIDFLAG -_COMMITSIG.fields_by_name[ - "timestamp" -].message_type = google_dot_protobuf_dot_timestamp__pb2._TIMESTAMP -_PROPOSAL.fields_by_name["type"].enum_type = _SIGNEDMSGTYPE -_PROPOSAL.fields_by_name["block_id"].message_type = _BLOCKID -_PROPOSAL.fields_by_name[ - "timestamp" -].message_type = google_dot_protobuf_dot_timestamp__pb2._TIMESTAMP -_SIGNEDHEADER.fields_by_name["header"].message_type = _HEADER -_SIGNEDHEADER.fields_by_name["commit"].message_type = _COMMIT -_LIGHTBLOCK.fields_by_name["signed_header"].message_type = _SIGNEDHEADER -_LIGHTBLOCK.fields_by_name[ - "validator_set" -].message_type = tendermint_dot_types_dot_validator__pb2._VALIDATORSET -_BLOCKMETA.fields_by_name["block_id"].message_type = _BLOCKID -_BLOCKMETA.fields_by_name["header"].message_type = _HEADER -_TXPROOF.fields_by_name[ - "proof" -].message_type = tendermint_dot_crypto_dot_proof__pb2._PROOF -DESCRIPTOR.message_types_by_name["PartSetHeader"] = _PARTSETHEADER -DESCRIPTOR.message_types_by_name["Part"] = _PART -DESCRIPTOR.message_types_by_name["BlockID"] = _BLOCKID -DESCRIPTOR.message_types_by_name["Header"] = _HEADER -DESCRIPTOR.message_types_by_name["Data"] = _DATA -DESCRIPTOR.message_types_by_name["Vote"] = _VOTE -DESCRIPTOR.message_types_by_name["Commit"] = _COMMIT -DESCRIPTOR.message_types_by_name["CommitSig"] = _COMMITSIG -DESCRIPTOR.message_types_by_name["Proposal"] = _PROPOSAL -DESCRIPTOR.message_types_by_name["SignedHeader"] = _SIGNEDHEADER -DESCRIPTOR.message_types_by_name["LightBlock"] = _LIGHTBLOCK -DESCRIPTOR.message_types_by_name["BlockMeta"] = _BLOCKMETA -DESCRIPTOR.message_types_by_name["TxProof"] = _TXPROOF -DESCRIPTOR.enum_types_by_name["BlockIDFlag"] = _BLOCKIDFLAG -DESCRIPTOR.enum_types_by_name["SignedMsgType"] = _SIGNEDMSGTYPE -_sym_db.RegisterFileDescriptor(DESCRIPTOR) - -PartSetHeader = _reflection.GeneratedProtocolMessageType( - "PartSetHeader", - (_message.Message,), - { - "DESCRIPTOR": _PARTSETHEADER, - "__module__": "tendermint.types.types_pb2" - # @@protoc_insertion_point(class_scope:tendermint.types.PartSetHeader) - }, -) -_sym_db.RegisterMessage(PartSetHeader) - -Part = _reflection.GeneratedProtocolMessageType( - "Part", - (_message.Message,), - { - "DESCRIPTOR": _PART, - "__module__": "tendermint.types.types_pb2" - # @@protoc_insertion_point(class_scope:tendermint.types.Part) - }, -) -_sym_db.RegisterMessage(Part) - -BlockID = _reflection.GeneratedProtocolMessageType( - "BlockID", - (_message.Message,), - { - "DESCRIPTOR": _BLOCKID, - "__module__": "tendermint.types.types_pb2" - # @@protoc_insertion_point(class_scope:tendermint.types.BlockID) - }, -) -_sym_db.RegisterMessage(BlockID) - -Header = _reflection.GeneratedProtocolMessageType( - "Header", - (_message.Message,), - { - "DESCRIPTOR": _HEADER, - "__module__": "tendermint.types.types_pb2" - # @@protoc_insertion_point(class_scope:tendermint.types.Header) - }, -) -_sym_db.RegisterMessage(Header) - -Data = _reflection.GeneratedProtocolMessageType( - "Data", - (_message.Message,), - { - "DESCRIPTOR": _DATA, - "__module__": "tendermint.types.types_pb2" - # @@protoc_insertion_point(class_scope:tendermint.types.Data) - }, -) -_sym_db.RegisterMessage(Data) - -Vote = _reflection.GeneratedProtocolMessageType( - "Vote", - (_message.Message,), - { - "DESCRIPTOR": _VOTE, - "__module__": "tendermint.types.types_pb2" - # @@protoc_insertion_point(class_scope:tendermint.types.Vote) - }, -) -_sym_db.RegisterMessage(Vote) - -Commit = _reflection.GeneratedProtocolMessageType( - "Commit", - (_message.Message,), - { - "DESCRIPTOR": _COMMIT, - "__module__": "tendermint.types.types_pb2" - # @@protoc_insertion_point(class_scope:tendermint.types.Commit) - }, -) -_sym_db.RegisterMessage(Commit) - -CommitSig = _reflection.GeneratedProtocolMessageType( - "CommitSig", - (_message.Message,), - { - "DESCRIPTOR": _COMMITSIG, - "__module__": "tendermint.types.types_pb2" - # @@protoc_insertion_point(class_scope:tendermint.types.CommitSig) - }, -) -_sym_db.RegisterMessage(CommitSig) - -Proposal = _reflection.GeneratedProtocolMessageType( - "Proposal", - (_message.Message,), - { - "DESCRIPTOR": _PROPOSAL, - "__module__": "tendermint.types.types_pb2" - # @@protoc_insertion_point(class_scope:tendermint.types.Proposal) - }, -) -_sym_db.RegisterMessage(Proposal) - -SignedHeader = _reflection.GeneratedProtocolMessageType( - "SignedHeader", - (_message.Message,), - { - "DESCRIPTOR": _SIGNEDHEADER, - "__module__": "tendermint.types.types_pb2" - # @@protoc_insertion_point(class_scope:tendermint.types.SignedHeader) - }, -) -_sym_db.RegisterMessage(SignedHeader) - -LightBlock = _reflection.GeneratedProtocolMessageType( - "LightBlock", - (_message.Message,), - { - "DESCRIPTOR": _LIGHTBLOCK, - "__module__": "tendermint.types.types_pb2" - # @@protoc_insertion_point(class_scope:tendermint.types.LightBlock) - }, -) -_sym_db.RegisterMessage(LightBlock) - -BlockMeta = _reflection.GeneratedProtocolMessageType( - "BlockMeta", - (_message.Message,), - { - "DESCRIPTOR": _BLOCKMETA, - "__module__": "tendermint.types.types_pb2" - # @@protoc_insertion_point(class_scope:tendermint.types.BlockMeta) - }, -) -_sym_db.RegisterMessage(BlockMeta) - -TxProof = _reflection.GeneratedProtocolMessageType( - "TxProof", - (_message.Message,), - { - "DESCRIPTOR": _TXPROOF, - "__module__": "tendermint.types.types_pb2" - # @@protoc_insertion_point(class_scope:tendermint.types.TxProof) - }, -) -_sym_db.RegisterMessage(TxProof) - - -DESCRIPTOR._options = None -_BLOCKIDFLAG._options = None -_BLOCKIDFLAG.values_by_name["BLOCK_ID_FLAG_UNKNOWN"]._options = None -_BLOCKIDFLAG.values_by_name["BLOCK_ID_FLAG_ABSENT"]._options = None -_BLOCKIDFLAG.values_by_name["BLOCK_ID_FLAG_COMMIT"]._options = None -_BLOCKIDFLAG.values_by_name["BLOCK_ID_FLAG_NIL"]._options = None -_SIGNEDMSGTYPE._options = None -_SIGNEDMSGTYPE.values_by_name["SIGNED_MSG_TYPE_UNKNOWN"]._options = None -_SIGNEDMSGTYPE.values_by_name["SIGNED_MSG_TYPE_PREVOTE"]._options = None -_SIGNEDMSGTYPE.values_by_name["SIGNED_MSG_TYPE_PRECOMMIT"]._options = None -_SIGNEDMSGTYPE.values_by_name["SIGNED_MSG_TYPE_PROPOSAL"]._options = None -_PART.fields_by_name["proof"]._options = None -_BLOCKID.fields_by_name["part_set_header"]._options = None -_HEADER.fields_by_name["version"]._options = None -_HEADER.fields_by_name["chain_id"]._options = None -_HEADER.fields_by_name["time"]._options = None -_HEADER.fields_by_name["last_block_id"]._options = None -_VOTE.fields_by_name["block_id"]._options = None -_VOTE.fields_by_name["timestamp"]._options = None -_COMMIT.fields_by_name["block_id"]._options = None -_COMMIT.fields_by_name["signatures"]._options = None -_COMMITSIG.fields_by_name["timestamp"]._options = None -_PROPOSAL.fields_by_name["block_id"]._options = None -_PROPOSAL.fields_by_name["timestamp"]._options = None -_BLOCKMETA.fields_by_name["block_id"]._options = None -_BLOCKMETA.fields_by_name["header"]._options = None +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile( + b'\n\x1ctendermint/types/types.proto\x12\x10tendermint.types\x1a\x14gogoproto/gogo.proto\x1a\x1fgoogle/protobuf/timestamp.proto\x1a\x1dtendermint/crypto/proof.proto\x1a\x1etendermint/version/types.proto\x1a tendermint/types/validator.proto",\n\rPartSetHeader\x12\r\n\x05total\x18\x01 \x01(\r\x12\x0c\n\x04hash\x18\x02 \x01(\x0c"S\n\x04Part\x12\r\n\x05index\x18\x01 \x01(\r\x12\r\n\x05\x62ytes\x18\x02 \x01(\x0c\x12-\n\x05proof\x18\x03 \x01(\x0b\x32\x18.tendermint.crypto.ProofB\x04\xc8\xde\x1f\x00"W\n\x07\x42lockID\x12\x0c\n\x04hash\x18\x01 \x01(\x0c\x12>\n\x0fpart_set_header\x18\x02 \x01(\x0b\x32\x1f.tendermint.types.PartSetHeaderB\x04\xc8\xde\x1f\x00"\xb3\x03\n\x06Header\x12\x34\n\x07version\x18\x01 \x01(\x0b\x32\x1d.tendermint.version.ConsensusB\x04\xc8\xde\x1f\x00\x12\x1d\n\x08\x63hain_id\x18\x02 \x01(\tB\x0b\xe2\xde\x1f\x07\x43hainID\x12\x0e\n\x06height\x18\x03 \x01(\x03\x12\x32\n\x04time\x18\x04 \x01(\x0b\x32\x1a.google.protobuf.TimestampB\x08\xc8\xde\x1f\x00\x90\xdf\x1f\x01\x12\x36\n\rlast_block_id\x18\x05 \x01(\x0b\x32\x19.tendermint.types.BlockIDB\x04\xc8\xde\x1f\x00\x12\x18\n\x10last_commit_hash\x18\x06 \x01(\x0c\x12\x11\n\tdata_hash\x18\x07 \x01(\x0c\x12\x17\n\x0fvalidators_hash\x18\x08 \x01(\x0c\x12\x1c\n\x14next_validators_hash\x18\t \x01(\x0c\x12\x16\n\x0e\x63onsensus_hash\x18\n \x01(\x0c\x12\x10\n\x08\x61pp_hash\x18\x0b \x01(\x0c\x12\x19\n\x11last_results_hash\x18\x0c \x01(\x0c\x12\x15\n\revidence_hash\x18\r \x01(\x0c\x12\x18\n\x10proposer_address\x18\x0e \x01(\x0c"\x13\n\x04\x44\x61ta\x12\x0b\n\x03txs\x18\x01 \x03(\x0c"\x92\x02\n\x04Vote\x12-\n\x04type\x18\x01 \x01(\x0e\x32\x1f.tendermint.types.SignedMsgType\x12\x0e\n\x06height\x18\x02 \x01(\x03\x12\r\n\x05round\x18\x03 \x01(\x05\x12<\n\x08\x62lock_id\x18\x04 \x01(\x0b\x32\x19.tendermint.types.BlockIDB\x0f\xc8\xde\x1f\x00\xe2\xde\x1f\x07\x42lockID\x12\x37\n\ttimestamp\x18\x05 \x01(\x0b\x32\x1a.google.protobuf.TimestampB\x08\xc8\xde\x1f\x00\x90\xdf\x1f\x01\x12\x19\n\x11validator_address\x18\x06 \x01(\x0c\x12\x17\n\x0fvalidator_index\x18\x07 \x01(\x05\x12\x11\n\tsignature\x18\x08 \x01(\x0c"\x9c\x01\n\x06\x43ommit\x12\x0e\n\x06height\x18\x01 \x01(\x03\x12\r\n\x05round\x18\x02 \x01(\x05\x12<\n\x08\x62lock_id\x18\x03 \x01(\x0b\x32\x19.tendermint.types.BlockIDB\x0f\xc8\xde\x1f\x00\xe2\xde\x1f\x07\x42lockID\x12\x35\n\nsignatures\x18\x04 \x03(\x0b\x32\x1b.tendermint.types.CommitSigB\x04\xc8\xde\x1f\x00"\xa8\x01\n\tCommitSig\x12\x34\n\rblock_id_flag\x18\x01 \x01(\x0e\x32\x1d.tendermint.types.BlockIDFlag\x12\x19\n\x11validator_address\x18\x02 \x01(\x0c\x12\x37\n\ttimestamp\x18\x03 \x01(\x0b\x32\x1a.google.protobuf.TimestampB\x08\xc8\xde\x1f\x00\x90\xdf\x1f\x01\x12\x11\n\tsignature\x18\x04 \x01(\x0c"\xf5\x01\n\x08Proposal\x12-\n\x04type\x18\x01 \x01(\x0e\x32\x1f.tendermint.types.SignedMsgType\x12\x0e\n\x06height\x18\x02 \x01(\x03\x12\r\n\x05round\x18\x03 \x01(\x05\x12\x11\n\tpol_round\x18\x04 \x01(\x05\x12<\n\x08\x62lock_id\x18\x05 \x01(\x0b\x32\x19.tendermint.types.BlockIDB\x0f\xc8\xde\x1f\x00\xe2\xde\x1f\x07\x42lockID\x12\x37\n\ttimestamp\x18\x06 \x01(\x0b\x32\x1a.google.protobuf.TimestampB\x08\xc8\xde\x1f\x00\x90\xdf\x1f\x01\x12\x11\n\tsignature\x18\x07 \x01(\x0c"b\n\x0cSignedHeader\x12(\n\x06header\x18\x01 \x01(\x0b\x32\x18.tendermint.types.Header\x12(\n\x06\x63ommit\x18\x02 \x01(\x0b\x32\x18.tendermint.types.Commit"z\n\nLightBlock\x12\x35\n\rsigned_header\x18\x01 \x01(\x0b\x32\x1e.tendermint.types.SignedHeader\x12\x35\n\rvalidator_set\x18\x02 \x01(\x0b\x32\x1e.tendermint.types.ValidatorSet"\x9e\x01\n\tBlockMeta\x12<\n\x08\x62lock_id\x18\x01 \x01(\x0b\x32\x19.tendermint.types.BlockIDB\x0f\xc8\xde\x1f\x00\xe2\xde\x1f\x07\x42lockID\x12\x12\n\nblock_size\x18\x02 \x01(\x03\x12.\n\x06header\x18\x03 \x01(\x0b\x32\x18.tendermint.types.HeaderB\x04\xc8\xde\x1f\x00\x12\x0f\n\x07num_txs\x18\x04 \x01(\x03"S\n\x07TxProof\x12\x11\n\troot_hash\x18\x01 \x01(\x0c\x12\x0c\n\x04\x64\x61ta\x18\x02 \x01(\x0c\x12\'\n\x05proof\x18\x03 \x01(\x0b\x32\x18.tendermint.crypto.Proof*\xd7\x01\n\x0b\x42lockIDFlag\x12\x31\n\x15\x42LOCK_ID_FLAG_UNKNOWN\x10\x00\x1a\x16\x8a\x9d \x12\x42lockIDFlagUnknown\x12/\n\x14\x42LOCK_ID_FLAG_ABSENT\x10\x01\x1a\x15\x8a\x9d \x11\x42lockIDFlagAbsent\x12/\n\x14\x42LOCK_ID_FLAG_COMMIT\x10\x02\x1a\x15\x8a\x9d \x11\x42lockIDFlagCommit\x12)\n\x11\x42LOCK_ID_FLAG_NIL\x10\x03\x1a\x12\x8a\x9d \x0e\x42lockIDFlagNil\x1a\x08\x88\xa3\x1e\x00\xa8\xa4\x1e\x01*\xd7\x01\n\rSignedMsgType\x12,\n\x17SIGNED_MSG_TYPE_UNKNOWN\x10\x00\x1a\x0f\x8a\x9d \x0bUnknownType\x12,\n\x17SIGNED_MSG_TYPE_PREVOTE\x10\x01\x1a\x0f\x8a\x9d \x0bPrevoteType\x12\x30\n\x19SIGNED_MSG_TYPE_PRECOMMIT\x10\x02\x1a\x11\x8a\x9d \rPrecommitType\x12.\n\x18SIGNED_MSG_TYPE_PROPOSAL\x10 \x1a\x10\x8a\x9d \x0cProposalType\x1a\x08\x88\xa3\x1e\x00\xa8\xa4\x1e\x01\x42\x39Z7github.com/tendermint/tendermint/proto/tendermint/typesb\x06proto3' +) + +_globals = globals() +_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) +_builder.BuildTopDescriptorsAndMessages( + DESCRIPTOR, "tendermint.types.types_pb2", _globals +) +if _descriptor._USE_C_DESCRIPTORS == False: + DESCRIPTOR._options = None + DESCRIPTOR._serialized_options = ( + b"Z7github.com/tendermint/tendermint/proto/tendermint/types" + ) + _BLOCKIDFLAG._options = None + _BLOCKIDFLAG._serialized_options = b"\210\243\036\000\250\244\036\001" + _BLOCKIDFLAG.values_by_name["BLOCK_ID_FLAG_UNKNOWN"]._options = None + _BLOCKIDFLAG.values_by_name[ + "BLOCK_ID_FLAG_UNKNOWN" + ]._serialized_options = b"\212\235 \022BlockIDFlagUnknown" + _BLOCKIDFLAG.values_by_name["BLOCK_ID_FLAG_ABSENT"]._options = None + _BLOCKIDFLAG.values_by_name[ + "BLOCK_ID_FLAG_ABSENT" + ]._serialized_options = b"\212\235 \021BlockIDFlagAbsent" + _BLOCKIDFLAG.values_by_name["BLOCK_ID_FLAG_COMMIT"]._options = None + _BLOCKIDFLAG.values_by_name[ + "BLOCK_ID_FLAG_COMMIT" + ]._serialized_options = b"\212\235 \021BlockIDFlagCommit" + _BLOCKIDFLAG.values_by_name["BLOCK_ID_FLAG_NIL"]._options = None + _BLOCKIDFLAG.values_by_name[ + "BLOCK_ID_FLAG_NIL" + ]._serialized_options = b"\212\235 \016BlockIDFlagNil" + _SIGNEDMSGTYPE._options = None + _SIGNEDMSGTYPE._serialized_options = b"\210\243\036\000\250\244\036\001" + _SIGNEDMSGTYPE.values_by_name["SIGNED_MSG_TYPE_UNKNOWN"]._options = None + _SIGNEDMSGTYPE.values_by_name[ + "SIGNED_MSG_TYPE_UNKNOWN" + ]._serialized_options = b"\212\235 \013UnknownType" + _SIGNEDMSGTYPE.values_by_name["SIGNED_MSG_TYPE_PREVOTE"]._options = None + _SIGNEDMSGTYPE.values_by_name[ + "SIGNED_MSG_TYPE_PREVOTE" + ]._serialized_options = b"\212\235 \013PrevoteType" + _SIGNEDMSGTYPE.values_by_name["SIGNED_MSG_TYPE_PRECOMMIT"]._options = None + _SIGNEDMSGTYPE.values_by_name[ + "SIGNED_MSG_TYPE_PRECOMMIT" + ]._serialized_options = b"\212\235 \rPrecommitType" + _SIGNEDMSGTYPE.values_by_name["SIGNED_MSG_TYPE_PROPOSAL"]._options = None + _SIGNEDMSGTYPE.values_by_name[ + "SIGNED_MSG_TYPE_PROPOSAL" + ]._serialized_options = b"\212\235 \014ProposalType" + _PART.fields_by_name["proof"]._options = None + _PART.fields_by_name["proof"]._serialized_options = b"\310\336\037\000" + _BLOCKID.fields_by_name["part_set_header"]._options = None + _BLOCKID.fields_by_name["part_set_header"]._serialized_options = b"\310\336\037\000" + _HEADER.fields_by_name["version"]._options = None + _HEADER.fields_by_name["version"]._serialized_options = b"\310\336\037\000" + _HEADER.fields_by_name["chain_id"]._options = None + _HEADER.fields_by_name["chain_id"]._serialized_options = b"\342\336\037\007ChainID" + _HEADER.fields_by_name["time"]._options = None + _HEADER.fields_by_name[ + "time" + ]._serialized_options = b"\310\336\037\000\220\337\037\001" + _HEADER.fields_by_name["last_block_id"]._options = None + _HEADER.fields_by_name["last_block_id"]._serialized_options = b"\310\336\037\000" + _VOTE.fields_by_name["block_id"]._options = None + _VOTE.fields_by_name[ + "block_id" + ]._serialized_options = b"\310\336\037\000\342\336\037\007BlockID" + _VOTE.fields_by_name["timestamp"]._options = None + _VOTE.fields_by_name[ + "timestamp" + ]._serialized_options = b"\310\336\037\000\220\337\037\001" + _COMMIT.fields_by_name["block_id"]._options = None + _COMMIT.fields_by_name[ + "block_id" + ]._serialized_options = b"\310\336\037\000\342\336\037\007BlockID" + _COMMIT.fields_by_name["signatures"]._options = None + _COMMIT.fields_by_name["signatures"]._serialized_options = b"\310\336\037\000" + _COMMITSIG.fields_by_name["timestamp"]._options = None + _COMMITSIG.fields_by_name[ + "timestamp" + ]._serialized_options = b"\310\336\037\000\220\337\037\001" + _PROPOSAL.fields_by_name["block_id"]._options = None + _PROPOSAL.fields_by_name[ + "block_id" + ]._serialized_options = b"\310\336\037\000\342\336\037\007BlockID" + _PROPOSAL.fields_by_name["timestamp"]._options = None + _PROPOSAL.fields_by_name[ + "timestamp" + ]._serialized_options = b"\310\336\037\000\220\337\037\001" + _BLOCKMETA.fields_by_name["block_id"]._options = None + _BLOCKMETA.fields_by_name[ + "block_id" + ]._serialized_options = b"\310\336\037\000\342\336\037\007BlockID" + _BLOCKMETA.fields_by_name["header"]._options = None + _BLOCKMETA.fields_by_name["header"]._serialized_options = b"\310\336\037\000" + _globals["_BLOCKIDFLAG"]._serialized_start = 2207 + _globals["_BLOCKIDFLAG"]._serialized_end = 2422 + _globals["_SIGNEDMSGTYPE"]._serialized_start = 2425 + _globals["_SIGNEDMSGTYPE"]._serialized_end = 2640 + _globals["_PARTSETHEADER"]._serialized_start = 202 + _globals["_PARTSETHEADER"]._serialized_end = 246 + _globals["_PART"]._serialized_start = 248 + _globals["_PART"]._serialized_end = 331 + _globals["_BLOCKID"]._serialized_start = 333 + _globals["_BLOCKID"]._serialized_end = 420 + _globals["_HEADER"]._serialized_start = 423 + _globals["_HEADER"]._serialized_end = 858 + _globals["_DATA"]._serialized_start = 860 + _globals["_DATA"]._serialized_end = 879 + _globals["_VOTE"]._serialized_start = 882 + _globals["_VOTE"]._serialized_end = 1156 + _globals["_COMMIT"]._serialized_start = 1159 + _globals["_COMMIT"]._serialized_end = 1315 + _globals["_COMMITSIG"]._serialized_start = 1318 + _globals["_COMMITSIG"]._serialized_end = 1486 + _globals["_PROPOSAL"]._serialized_start = 1489 + _globals["_PROPOSAL"]._serialized_end = 1734 + _globals["_SIGNEDHEADER"]._serialized_start = 1736 + _globals["_SIGNEDHEADER"]._serialized_end = 1834 + _globals["_LIGHTBLOCK"]._serialized_start = 1836 + _globals["_LIGHTBLOCK"]._serialized_end = 1958 + _globals["_BLOCKMETA"]._serialized_start = 1961 + _globals["_BLOCKMETA"]._serialized_end = 2119 + _globals["_TXPROOF"]._serialized_start = 2121 + _globals["_TXPROOF"]._serialized_end = 2204 # @@protoc_insertion_point(module_scope) diff --git a/packages/valory/connections/abci/tendermint/types/validator_pb2.py b/packages/valory/connections/abci/tendermint/types/validator_pb2.py index 48d58887ff..990e243ee3 100644 --- a/packages/valory/connections/abci/tendermint/types/validator_pb2.py +++ b/packages/valory/connections/abci/tendermint/types/validator_pb2.py @@ -3,9 +3,9 @@ # source: tendermint/types/validator.proto """Generated protocol buffer code.""" from google.protobuf import descriptor as _descriptor -from google.protobuf import message as _message -from google.protobuf import reflection as _reflection +from google.protobuf import descriptor_pool as _descriptor_pool from google.protobuf import symbol_database as _symbol_database +from google.protobuf.internal import builder as _builder # @@protoc_insertion_point(imports) @@ -21,303 +21,26 @@ ) -DESCRIPTOR = _descriptor.FileDescriptor( - name="tendermint/types/validator.proto", - package="tendermint.types", - syntax="proto3", - serialized_options=b"Z7github.com/tendermint/tendermint/proto/tendermint/types", - create_key=_descriptor._internal_create_key, - serialized_pb=b'\n tendermint/types/validator.proto\x12\x10tendermint.types\x1a\x14gogoproto/gogo.proto\x1a\x1ctendermint/crypto/keys.proto"\x8a\x01\n\x0cValidatorSet\x12/\n\nvalidators\x18\x01 \x03(\x0b\x32\x1b.tendermint.types.Validator\x12-\n\x08proposer\x18\x02 \x01(\x0b\x32\x1b.tendermint.types.Validator\x12\x1a\n\x12total_voting_power\x18\x03 \x01(\x03"\x82\x01\n\tValidator\x12\x0f\n\x07\x61\x64\x64ress\x18\x01 \x01(\x0c\x12\x33\n\x07pub_key\x18\x02 \x01(\x0b\x32\x1c.tendermint.crypto.PublicKeyB\x04\xc8\xde\x1f\x00\x12\x14\n\x0cvoting_power\x18\x03 \x01(\x03\x12\x19\n\x11proposer_priority\x18\x04 \x01(\x03"V\n\x0fSimpleValidator\x12-\n\x07pub_key\x18\x01 \x01(\x0b\x32\x1c.tendermint.crypto.PublicKey\x12\x14\n\x0cvoting_power\x18\x02 \x01(\x03\x42\x39Z7github.com/tendermint/tendermint/proto/tendermint/typesb\x06proto3', - dependencies=[ - gogoproto_dot_gogo__pb2.DESCRIPTOR, - tendermint_dot_crypto_dot_keys__pb2.DESCRIPTOR, - ], +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile( + b'\n tendermint/types/validator.proto\x12\x10tendermint.types\x1a\x14gogoproto/gogo.proto\x1a\x1ctendermint/crypto/keys.proto"\x8a\x01\n\x0cValidatorSet\x12/\n\nvalidators\x18\x01 \x03(\x0b\x32\x1b.tendermint.types.Validator\x12-\n\x08proposer\x18\x02 \x01(\x0b\x32\x1b.tendermint.types.Validator\x12\x1a\n\x12total_voting_power\x18\x03 \x01(\x03"\x82\x01\n\tValidator\x12\x0f\n\x07\x61\x64\x64ress\x18\x01 \x01(\x0c\x12\x33\n\x07pub_key\x18\x02 \x01(\x0b\x32\x1c.tendermint.crypto.PublicKeyB\x04\xc8\xde\x1f\x00\x12\x14\n\x0cvoting_power\x18\x03 \x01(\x03\x12\x19\n\x11proposer_priority\x18\x04 \x01(\x03"V\n\x0fSimpleValidator\x12-\n\x07pub_key\x18\x01 \x01(\x0b\x32\x1c.tendermint.crypto.PublicKey\x12\x14\n\x0cvoting_power\x18\x02 \x01(\x03\x42\x39Z7github.com/tendermint/tendermint/proto/tendermint/typesb\x06proto3' ) - -_VALIDATORSET = _descriptor.Descriptor( - name="ValidatorSet", - full_name="tendermint.types.ValidatorSet", - filename=None, - file=DESCRIPTOR, - containing_type=None, - create_key=_descriptor._internal_create_key, - fields=[ - _descriptor.FieldDescriptor( - name="validators", - full_name="tendermint.types.ValidatorSet.validators", - index=0, - number=1, - type=11, - cpp_type=10, - label=3, - has_default_value=False, - default_value=[], - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="proposer", - full_name="tendermint.types.ValidatorSet.proposer", - index=1, - number=2, - type=11, - cpp_type=10, - label=1, - has_default_value=False, - default_value=None, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="total_voting_power", - full_name="tendermint.types.ValidatorSet.total_voting_power", - index=2, - number=3, - type=3, - cpp_type=2, - label=1, - has_default_value=False, - default_value=0, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - ], - extensions=[], - nested_types=[], - enum_types=[], - serialized_options=None, - is_extendable=False, - syntax="proto3", - extension_ranges=[], - oneofs=[], - serialized_start=107, - serialized_end=245, -) - - -_VALIDATOR = _descriptor.Descriptor( - name="Validator", - full_name="tendermint.types.Validator", - filename=None, - file=DESCRIPTOR, - containing_type=None, - create_key=_descriptor._internal_create_key, - fields=[ - _descriptor.FieldDescriptor( - name="address", - full_name="tendermint.types.Validator.address", - index=0, - number=1, - type=12, - cpp_type=9, - label=1, - has_default_value=False, - default_value=b"", - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="pub_key", - full_name="tendermint.types.Validator.pub_key", - index=1, - number=2, - type=11, - cpp_type=10, - label=1, - has_default_value=False, - default_value=None, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=b"\310\336\037\000", - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="voting_power", - full_name="tendermint.types.Validator.voting_power", - index=2, - number=3, - type=3, - cpp_type=2, - label=1, - has_default_value=False, - default_value=0, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="proposer_priority", - full_name="tendermint.types.Validator.proposer_priority", - index=3, - number=4, - type=3, - cpp_type=2, - label=1, - has_default_value=False, - default_value=0, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - ], - extensions=[], - nested_types=[], - enum_types=[], - serialized_options=None, - is_extendable=False, - syntax="proto3", - extension_ranges=[], - oneofs=[], - serialized_start=248, - serialized_end=378, -) - - -_SIMPLEVALIDATOR = _descriptor.Descriptor( - name="SimpleValidator", - full_name="tendermint.types.SimpleValidator", - filename=None, - file=DESCRIPTOR, - containing_type=None, - create_key=_descriptor._internal_create_key, - fields=[ - _descriptor.FieldDescriptor( - name="pub_key", - full_name="tendermint.types.SimpleValidator.pub_key", - index=0, - number=1, - type=11, - cpp_type=10, - label=1, - has_default_value=False, - default_value=None, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="voting_power", - full_name="tendermint.types.SimpleValidator.voting_power", - index=1, - number=2, - type=3, - cpp_type=2, - label=1, - has_default_value=False, - default_value=0, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - ], - extensions=[], - nested_types=[], - enum_types=[], - serialized_options=None, - is_extendable=False, - syntax="proto3", - extension_ranges=[], - oneofs=[], - serialized_start=380, - serialized_end=466, -) - -_VALIDATORSET.fields_by_name["validators"].message_type = _VALIDATOR -_VALIDATORSET.fields_by_name["proposer"].message_type = _VALIDATOR -_VALIDATOR.fields_by_name[ - "pub_key" -].message_type = tendermint_dot_crypto_dot_keys__pb2._PUBLICKEY -_SIMPLEVALIDATOR.fields_by_name[ - "pub_key" -].message_type = tendermint_dot_crypto_dot_keys__pb2._PUBLICKEY -DESCRIPTOR.message_types_by_name["ValidatorSet"] = _VALIDATORSET -DESCRIPTOR.message_types_by_name["Validator"] = _VALIDATOR -DESCRIPTOR.message_types_by_name["SimpleValidator"] = _SIMPLEVALIDATOR -_sym_db.RegisterFileDescriptor(DESCRIPTOR) - -ValidatorSet = _reflection.GeneratedProtocolMessageType( - "ValidatorSet", - (_message.Message,), - { - "DESCRIPTOR": _VALIDATORSET, - "__module__": "tendermint.types.validator_pb2" - # @@protoc_insertion_point(class_scope:tendermint.types.ValidatorSet) - }, -) -_sym_db.RegisterMessage(ValidatorSet) - -Validator = _reflection.GeneratedProtocolMessageType( - "Validator", - (_message.Message,), - { - "DESCRIPTOR": _VALIDATOR, - "__module__": "tendermint.types.validator_pb2" - # @@protoc_insertion_point(class_scope:tendermint.types.Validator) - }, +_globals = globals() +_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) +_builder.BuildTopDescriptorsAndMessages( + DESCRIPTOR, "tendermint.types.validator_pb2", _globals ) -_sym_db.RegisterMessage(Validator) - -SimpleValidator = _reflection.GeneratedProtocolMessageType( - "SimpleValidator", - (_message.Message,), - { - "DESCRIPTOR": _SIMPLEVALIDATOR, - "__module__": "tendermint.types.validator_pb2" - # @@protoc_insertion_point(class_scope:tendermint.types.SimpleValidator) - }, -) -_sym_db.RegisterMessage(SimpleValidator) - - -DESCRIPTOR._options = None -_VALIDATOR.fields_by_name["pub_key"]._options = None +if _descriptor._USE_C_DESCRIPTORS == False: + DESCRIPTOR._options = None + DESCRIPTOR._serialized_options = ( + b"Z7github.com/tendermint/tendermint/proto/tendermint/types" + ) + _VALIDATOR.fields_by_name["pub_key"]._options = None + _VALIDATOR.fields_by_name["pub_key"]._serialized_options = b"\310\336\037\000" + _globals["_VALIDATORSET"]._serialized_start = 107 + _globals["_VALIDATORSET"]._serialized_end = 245 + _globals["_VALIDATOR"]._serialized_start = 248 + _globals["_VALIDATOR"]._serialized_end = 378 + _globals["_SIMPLEVALIDATOR"]._serialized_start = 380 + _globals["_SIMPLEVALIDATOR"]._serialized_end = 466 # @@protoc_insertion_point(module_scope) diff --git a/packages/valory/connections/abci/tendermint/version/types_pb2.py b/packages/valory/connections/abci/tendermint/version/types_pb2.py index a5e2bc1656..46fcbdf527 100644 --- a/packages/valory/connections/abci/tendermint/version/types_pb2.py +++ b/packages/valory/connections/abci/tendermint/version/types_pb2.py @@ -3,9 +3,9 @@ # source: tendermint/version/types.proto """Generated protocol buffer code.""" from google.protobuf import descriptor as _descriptor -from google.protobuf import message as _message -from google.protobuf import reflection as _reflection +from google.protobuf import descriptor_pool as _descriptor_pool from google.protobuf import symbol_database as _symbol_database +from google.protobuf.internal import builder as _builder # @@protoc_insertion_point(imports) @@ -18,165 +18,24 @@ ) -DESCRIPTOR = _descriptor.FileDescriptor( - name="tendermint/version/types.proto", - package="tendermint.version", - syntax="proto3", - serialized_options=b"Z9github.com/tendermint/tendermint/proto/tendermint/version", - create_key=_descriptor._internal_create_key, - serialized_pb=b'\n\x1etendermint/version/types.proto\x12\x12tendermint.version\x1a\x14gogoproto/gogo.proto")\n\x03\x41pp\x12\x10\n\x08protocol\x18\x01 \x01(\x04\x12\x10\n\x08software\x18\x02 \x01(\t"-\n\tConsensus\x12\r\n\x05\x62lock\x18\x01 \x01(\x04\x12\x0b\n\x03\x61pp\x18\x02 \x01(\x04:\x04\xe8\xa0\x1f\x01\x42;Z9github.com/tendermint/tendermint/proto/tendermint/versionb\x06proto3', - dependencies=[ - gogoproto_dot_gogo__pb2.DESCRIPTOR, - ], +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile( + b'\n\x1etendermint/version/types.proto\x12\x12tendermint.version\x1a\x14gogoproto/gogo.proto")\n\x03\x41pp\x12\x10\n\x08protocol\x18\x01 \x01(\x04\x12\x10\n\x08software\x18\x02 \x01(\t"-\n\tConsensus\x12\r\n\x05\x62lock\x18\x01 \x01(\x04\x12\x0b\n\x03\x61pp\x18\x02 \x01(\x04:\x04\xe8\xa0\x1f\x01\x42;Z9github.com/tendermint/tendermint/proto/tendermint/versionb\x06proto3' ) - -_APP = _descriptor.Descriptor( - name="App", - full_name="tendermint.version.App", - filename=None, - file=DESCRIPTOR, - containing_type=None, - create_key=_descriptor._internal_create_key, - fields=[ - _descriptor.FieldDescriptor( - name="protocol", - full_name="tendermint.version.App.protocol", - index=0, - number=1, - type=4, - cpp_type=4, - label=1, - has_default_value=False, - default_value=0, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="software", - full_name="tendermint.version.App.software", - index=1, - number=2, - type=9, - cpp_type=9, - label=1, - has_default_value=False, - default_value=b"".decode("utf-8"), - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - ], - extensions=[], - nested_types=[], - enum_types=[], - serialized_options=None, - is_extendable=False, - syntax="proto3", - extension_ranges=[], - oneofs=[], - serialized_start=76, - serialized_end=117, -) - - -_CONSENSUS = _descriptor.Descriptor( - name="Consensus", - full_name="tendermint.version.Consensus", - filename=None, - file=DESCRIPTOR, - containing_type=None, - create_key=_descriptor._internal_create_key, - fields=[ - _descriptor.FieldDescriptor( - name="block", - full_name="tendermint.version.Consensus.block", - index=0, - number=1, - type=4, - cpp_type=4, - label=1, - has_default_value=False, - default_value=0, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - _descriptor.FieldDescriptor( - name="app", - full_name="tendermint.version.Consensus.app", - index=1, - number=2, - type=4, - cpp_type=4, - label=1, - has_default_value=False, - default_value=0, - message_type=None, - enum_type=None, - containing_type=None, - is_extension=False, - extension_scope=None, - serialized_options=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - ), - ], - extensions=[], - nested_types=[], - enum_types=[], - serialized_options=b"\350\240\037\001", - is_extendable=False, - syntax="proto3", - extension_ranges=[], - oneofs=[], - serialized_start=119, - serialized_end=164, +_globals = globals() +_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) +_builder.BuildTopDescriptorsAndMessages( + DESCRIPTOR, "tendermint.version.types_pb2", _globals ) - -DESCRIPTOR.message_types_by_name["App"] = _APP -DESCRIPTOR.message_types_by_name["Consensus"] = _CONSENSUS -_sym_db.RegisterFileDescriptor(DESCRIPTOR) - -App = _reflection.GeneratedProtocolMessageType( - "App", - (_message.Message,), - { - "DESCRIPTOR": _APP, - "__module__": "tendermint.version.types_pb2" - # @@protoc_insertion_point(class_scope:tendermint.version.App) - }, -) -_sym_db.RegisterMessage(App) - -Consensus = _reflection.GeneratedProtocolMessageType( - "Consensus", - (_message.Message,), - { - "DESCRIPTOR": _CONSENSUS, - "__module__": "tendermint.version.types_pb2" - # @@protoc_insertion_point(class_scope:tendermint.version.Consensus) - }, -) -_sym_db.RegisterMessage(Consensus) - - -DESCRIPTOR._options = None -_CONSENSUS._options = None +if _descriptor._USE_C_DESCRIPTORS == False: + DESCRIPTOR._options = None + DESCRIPTOR._serialized_options = ( + b"Z9github.com/tendermint/tendermint/proto/tendermint/version" + ) + _CONSENSUS._options = None + _CONSENSUS._serialized_options = b"\350\240\037\001" + _globals["_APP"]._serialized_start = 76 + _globals["_APP"]._serialized_end = 117 + _globals["_CONSENSUS"]._serialized_start = 119 + _globals["_CONSENSUS"]._serialized_end = 164 # @@protoc_insertion_point(module_scope) diff --git a/packages/valory/connections/abci/tendermint_decoder.py b/packages/valory/connections/abci/tendermint_decoder.py index 55003f4ce6..a50a501fac 100644 --- a/packages/valory/connections/abci/tendermint_decoder.py +++ b/packages/valory/connections/abci/tendermint_decoder.py @@ -31,11 +31,11 @@ from packages.valory.connections.abci.tendermint.abci.types_pb2 import ( # type: ignore Evidence as EvidencePb, ) -from packages.valory.connections.abci.tendermint.abci.types_pb2 import ( +from packages.valory.connections.abci.tendermint.abci.types_pb2 import ( # type: ignore LastCommitInfo as LastCommitInfoPb, ) -from packages.valory.connections.abci.tendermint.abci.types_pb2 import Request -from packages.valory.connections.abci.tendermint.abci.types_pb2 import ( +from packages.valory.connections.abci.tendermint.abci.types_pb2 import Request # type: ignore +from packages.valory.connections.abci.tendermint.abci.types_pb2 import ( # type: ignore Validator as ValidatorPb, ) from packages.valory.connections.abci.tendermint.types.types_pb2 import ( # type: ignore @@ -60,10 +60,10 @@ ) -from packages.valory.connections.abci.tendermint.abci.types_pb2 import ( # isort:skip +from packages.valory.connections.abci.tendermint.abci.types_pb2 import ( # type: ignore # isort:skip ConsensusParams as ConsensusParamsPb, ) -from packages.valory.connections.abci.tendermint.abci.types_pb2 import ( # isort:skip +from packages.valory.connections.abci.tendermint.abci.types_pb2 import ( # type: ignore # isort:skip ValidatorUpdate as ValidatorUpdatePb, ) diff --git a/packages/valory/connections/abci/tendermint_encoder.py b/packages/valory/connections/abci/tendermint_encoder.py index 2c329c8cda..47b9d10411 100644 --- a/packages/valory/connections/abci/tendermint_encoder.py +++ b/packages/valory/connections/abci/tendermint_encoder.py @@ -388,7 +388,6 @@ def _encode_validator_update( @classmethod def _encode_event(cls, event: CustomEvent) -> Event: - attributes_pb = [] for attribute in event.attributes: attribute_pb = EventAttribute() @@ -402,7 +401,6 @@ def _encode_event(cls, event: CustomEvent) -> Event: @classmethod def _encode_proof_ops(cls, proof_ops: CustomProofOps) -> ProofOps: - ops_pb = [] for proof_op in proof_ops.proof_ops: proof_op_pb = ProofOp() diff --git a/packages/valory/connections/abci/tests/__init__.py b/packages/valory/connections/abci/tests/__init__.py index b4d76edca4..0a13f49637 100644 --- a/packages/valory/connections/abci/tests/__init__.py +++ b/packages/valory/connections/abci/tests/__init__.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- # ------------------------------------------------------------------------------ # -# Copyright 2021-2022 Valory AG +# Copyright 2021-2023 Valory AG # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -18,3 +18,10 @@ # ------------------------------------------------------------------------------ """Tests package for valory/abci connection.""" + +from hypothesis import settings + + +CI = "CI" # pragma: nocover + +settings.register_profile(CI, deadline=5000) # pragma: nocover diff --git a/packages/valory/connections/abci/tests/helper.py b/packages/valory/connections/abci/tests/helper.py index 6eec895fa1..da6e982df0 100644 --- a/packages/valory/connections/abci/tests/helper.py +++ b/packages/valory/connections/abci/tests/helper.py @@ -356,7 +356,6 @@ def _get_message_content(message: Any) -> Node: # but are retrieved as mapping from Tendermint side assert message.IsInitialized() - assert not message.UnknownFields() assert not message.FindInitializationErrors() # NOTE: ListFields does not retrieve what is empty! @@ -406,7 +405,6 @@ def get_tendermint_content(envelope: Union[Request, Response]) -> Node: assert isinstance(envelope, (Request, Response)) assert envelope.IsInitialized() - assert not envelope.UnknownFields() assert not envelope.FindInitializationErrors() assert len(envelope.ListFields()) == 1 descr, message = envelope.ListFields()[0] @@ -424,7 +422,6 @@ def compare_trees(init_node: Node, tender_node: Node) -> None: return for k, init_child in init_node.items(): - # translate key to tendermint key tk = {"type_": "type", "format_": "format", "hash_": "hash"}.get(k, k) tender_child = tender_node[tk] @@ -438,7 +435,6 @@ def compare_trees(init_node: Node, tender_node: Node) -> None: compare_trees(init_child, tender_child) elif isinstance(tender_child, list): - # we use a nested mapping to represent a custom class, # tendermint doesn't use this for storing repeated fields if isinstance(init_child, dict): @@ -461,7 +457,6 @@ def _process_message_descriptor(m_descriptor: Any) -> Node: node: Node = {} for name, field in m_descriptor.fields_by_name.items(): - if field.message_type: cls = set_repr(field.message_type._concrete_class) node[name] = cls, _process_message_descriptor(cls.DESCRIPTOR) diff --git a/packages/valory/connections/abci/tests/test_abci_fuzz.py b/packages/valory/connections/abci/tests/test_abci_fuzz.py index acdada599a..9a978b0802 100644 --- a/packages/valory/connections/abci/tests/test_abci_fuzz.py +++ b/packages/valory/connections/abci/tests/test_abci_fuzz.py @@ -99,7 +99,6 @@ def _translate(aea_type_node: Node, tender_type_node: Node) -> Node: """ for key, type_child in aea_type_node.items(): - if is_enum(type_child): continue if key == "pub_key": @@ -325,7 +324,6 @@ def make_tendermint_test_method(message_key: str, strategy: Node) -> Callable: @settings(deadline=5000, suppress_health_check=[HealthCheck.too_slow]) @given(st.fixed_dictionaries({message_key: strategy})) def test_method(self: Any, conjecture: Node) -> None: - request = Request(**conjecture) assert decode(request) diff --git a/packages/valory/connections/abci/tests/test_fuzz/base.py b/packages/valory/connections/abci/tests/test_fuzz/base.py index f0c6f7d077..d054f06949 100644 --- a/packages/valory/connections/abci/tests/test_fuzz/base.py +++ b/packages/valory/connections/abci/tests/test_fuzz/base.py @@ -25,13 +25,12 @@ from pathlib import Path from typing import Any, Dict, List, Tuple, Type -import numpy as np from aea.exceptions import enforce from aea.test_tools.test_cases import AEATestCaseMany from hypothesis import given, settings from hypothesis.strategies import binary, booleans, integers, lists, text, tuples -from packages.valory.connections.abci import CI +from packages.valory.connections.abci.tests import CI from packages.valory.connections.abci.tests.test_fuzz.mock_node.channels.base import ( BaseChannel, ) @@ -50,15 +49,15 @@ class BaseFuzzyTests(AEATestCaseMany): package_registry_src_rel = Path(__file__).parents[5] - UINT_64_MAX_VALUE = np.iinfo(np.uint64).max + UINT_64_MAX_VALUE = 18446744073709551615 UINT_64_MIN_VALUE = 0 - INT_64_MAX_VALUE = np.iinfo(np.int64).max - INT_64_MIN_VALUE = np.iinfo(np.int64).min + INT_64_MAX_VALUE = 9223372036854775807 + INT_64_MIN_VALUE = -9223372036854775808 - UINT_32_MAX_VALUE = np.iinfo(np.uint32).max + UINT_32_MAX_VALUE = 4294967295 UINT_32_MIN_VALUE = 0 - INT_32_MAX_VALUE = np.iinfo(np.int32).max - INT_32_MIN_VALUE = np.iinfo(np.int32).min + INT_32_MAX_VALUE = 2147483647 + INT_32_MIN_VALUE = -2147483648 CHANNEL_TYPE: Type[BaseChannel] = BaseChannel CHANNEL_ARGS: Dict[str, Any] = dict() diff --git a/packages/valory/connections/abci/tests/test_fuzz/mock_node/channels/base.py b/packages/valory/connections/abci/tests/test_fuzz/mock_node/channels/base.py index 695076a4fd..5f790294df 100644 --- a/packages/valory/connections/abci/tests/test_fuzz/mock_node/channels/base.py +++ b/packages/valory/connections/abci/tests/test_fuzz/mock_node/channels/base.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- # ------------------------------------------------------------------------------ # -# Copyright 2021-2022 Valory AG +# Copyright 2021-2023 Valory AG # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -16,7 +16,11 @@ # limitations under the License. # # ------------------------------------------------------------------------------ + +# pylint: disable=no-member + """BaseChannel for MockNode""" + from typing import Dict import packages.valory.connections.abci.tendermint.abci.types_pb2 as abci_types # type: ignore @@ -42,7 +46,7 @@ def disconnect(self) -> None: By default, it is a no-op. """ - def send_info(self, request: abci_types.RequestInfo) -> abci_types.ResponseInfo: + def send_info(self, request: abci_types.RequestInfo) -> abci_types.ResponseInfo: # type: ignore """ Sends an info request. @@ -50,7 +54,7 @@ def send_info(self, request: abci_types.RequestInfo) -> abci_types.ResponseInfo: """ raise NotImplementedError - def send_echo(self, request: abci_types.RequestEcho) -> abci_types.ResponseEcho: + def send_echo(self, request: abci_types.RequestEcho) -> abci_types.ResponseEcho: # type: ignore """ Sends an echo request. @@ -58,7 +62,7 @@ def send_echo(self, request: abci_types.RequestEcho) -> abci_types.ResponseEcho: """ raise NotImplementedError - def send_flush(self, request: abci_types.RequestFlush) -> abci_types.ResponseFlush: + def send_flush(self, request: abci_types.RequestFlush) -> abci_types.ResponseFlush: # type: ignore """ Sends an flush request. @@ -67,8 +71,8 @@ def send_flush(self, request: abci_types.RequestFlush) -> abci_types.ResponseFlu raise NotImplementedError def send_set_option( - self, request: abci_types.RequestSetOption - ) -> abci_types.ResponseSetOption: + self, request: abci_types.RequestSetOption # type: ignore + ) -> abci_types.ResponseSetOption: # type: ignore """ Sends an setOption request. @@ -77,8 +81,8 @@ def send_set_option( raise NotImplementedError def send_deliver_tx( - self, request: abci_types.RequestDeliverTx - ) -> abci_types.ResponseDeliverTx: + self, request: abci_types.RequestDeliverTx # type: ignore + ) -> abci_types.ResponseDeliverTx: # type: ignore """ Sends an deliverTx request. @@ -87,8 +91,8 @@ def send_deliver_tx( raise NotImplementedError def send_check_tx( - self, request: abci_types.RequestCheckTx - ) -> abci_types.ResponseCheckTx: + self, request: abci_types.RequestCheckTx # type: ignore + ) -> abci_types.ResponseCheckTx: # type: ignore """ Sends an checkTx request. @@ -96,7 +100,7 @@ def send_check_tx( """ raise NotImplementedError - def send_query(self, request: abci_types.RequestQuery) -> abci_types.ResponseQuery: + def send_query(self, request: abci_types.RequestQuery) -> abci_types.ResponseQuery: # type: ignore """ Sends an query request. @@ -105,8 +109,8 @@ def send_query(self, request: abci_types.RequestQuery) -> abci_types.ResponseQue raise NotImplementedError def send_commit( - self, request: abci_types.RequestCommit - ) -> abci_types.ResponseCommit: + self, request: abci_types.RequestCommit # type: ignore + ) -> abci_types.ResponseCommit: # type: ignore """ Sends an commit request. @@ -115,8 +119,8 @@ def send_commit( raise NotImplementedError def send_init_chain( - self, request: abci_types.RequestInitChain - ) -> abci_types.ResponseInitChain: + self, request: abci_types.RequestInitChain # type: ignore + ) -> abci_types.ResponseInitChain: # type: ignore """ Sends an initChain request. @@ -125,8 +129,8 @@ def send_init_chain( raise NotImplementedError def send_begin_block( - self, request: abci_types.RequestBeginBlock - ) -> abci_types.ResponseBeginBlock: + self, request: abci_types.RequestBeginBlock # type: ignore + ) -> abci_types.ResponseBeginBlock: # type: ignore """ Sends an beginBlock request. @@ -135,8 +139,8 @@ def send_begin_block( raise NotImplementedError def send_end_block( - self, request: abci_types.RequestEndBlock - ) -> abci_types.ResponseEndBlock: + self, request: abci_types.RequestEndBlock # type: ignore + ) -> abci_types.ResponseEndBlock: # type: ignore """ Sends an endBlock request. @@ -145,8 +149,8 @@ def send_end_block( raise NotImplementedError def send_list_snapshots( - self, request: abci_types.RequestListSnapshots - ) -> abci_types.ResponseListSnapshots: + self, request: abci_types.RequestListSnapshots # type: ignore + ) -> abci_types.ResponseListSnapshots: # type: ignore """ Sends an listSnapshots request. @@ -155,8 +159,8 @@ def send_list_snapshots( raise NotImplementedError def send_offer_snapshot( - self, request: abci_types.RequestOfferSnapshot - ) -> abci_types.ResponseOfferSnapshot: + self, request: abci_types.RequestOfferSnapshot # type: ignore + ) -> abci_types.ResponseOfferSnapshot: # type: ignore """ Sends an offerSnapshot request. @@ -165,8 +169,8 @@ def send_offer_snapshot( raise NotImplementedError def send_load_snapshot_chunk( - self, request: abci_types.RequestLoadSnapshotChunk - ) -> abci_types.ResponseLoadSnapshotChunk: + self, request: abci_types.RequestLoadSnapshotChunk # type: ignore + ) -> abci_types.ResponseLoadSnapshotChunk: # type: ignore """ Sends an loadSnapshotChunk request. @@ -175,8 +179,8 @@ def send_load_snapshot_chunk( raise NotImplementedError def send_apply_snapshot_chunk( - self, request: abci_types.RequestApplySnapshotChunk - ) -> abci_types.ResponseApplySnapshotChunk: + self, request: abci_types.RequestApplySnapshotChunk # type: ignore + ) -> abci_types.ResponseApplySnapshotChunk: # type: ignore """ Sends an applySnapshotChunk request. diff --git a/packages/valory/connections/abci/tests/test_fuzz/mock_node/channels/grpc_channel.py b/packages/valory/connections/abci/tests/test_fuzz/mock_node/channels/grpc_channel.py index 8045445380..f247815cd0 100644 --- a/packages/valory/connections/abci/tests/test_fuzz/mock_node/channels/grpc_channel.py +++ b/packages/valory/connections/abci/tests/test_fuzz/mock_node/channels/grpc_channel.py @@ -55,7 +55,7 @@ def __init__(self, **kwargs: Dict) -> None: grpc_channel = grpc.insecure_channel(f"{host}:{port}") self.grpc_client = tendermint_grpc.ABCIApplicationStub(grpc_channel) - def send_info(self, request: abci_types.RequestInfo) -> abci_types.ResponseInfo: + def send_info(self, request: abci_types.RequestInfo) -> abci_types.ResponseInfo: # type: ignore """ Sends an info request. @@ -64,7 +64,7 @@ def send_info(self, request: abci_types.RequestInfo) -> abci_types.ResponseInfo: """ return self.grpc_client.Info(request) - def send_echo(self, request: abci_types.RequestEcho) -> abci_types.ResponseEcho: + def send_echo(self, request: abci_types.RequestEcho) -> abci_types.ResponseEcho: # type: ignore """ Sends an echo request. @@ -73,7 +73,7 @@ def send_echo(self, request: abci_types.RequestEcho) -> abci_types.ResponseEcho: """ return self.grpc_client.Echo(request) - def send_flush(self, request: abci_types.RequestFlush) -> abci_types.ResponseFlush: + def send_flush(self, request: abci_types.RequestFlush) -> abci_types.ResponseFlush: # type: ignore """ Sends an flush request. @@ -83,8 +83,8 @@ def send_flush(self, request: abci_types.RequestFlush) -> abci_types.ResponseFlu return self.grpc_client.Flush(request) def send_set_option( - self, request: abci_types.RequestSetOption - ) -> abci_types.ResponseSetOption: + self, request: abci_types.RequestSetOption # type: ignore + ) -> abci_types.ResponseSetOption: # type: ignore """ Sends an setOption request. @@ -94,8 +94,8 @@ def send_set_option( return self.grpc_client.SetOption(request) def send_deliver_tx( - self, request: abci_types.RequestDeliverTx - ) -> abci_types.ResponseDeliverTx: + self, request: abci_types.RequestDeliverTx # type: ignore + ) -> abci_types.ResponseDeliverTx: # type: ignore """ Sends an deliverTx request. @@ -105,8 +105,8 @@ def send_deliver_tx( return self.grpc_client.DeliverTx(request) def send_check_tx( - self, request: abci_types.RequestCheckTx - ) -> abci_types.ResponseCheckTx: + self, request: abci_types.RequestCheckTx # type: ignore + ) -> abci_types.ResponseCheckTx: # type: ignore """ Sends an checkTx request. @@ -115,7 +115,7 @@ def send_check_tx( """ return self.grpc_client.CheckTx(request) - def send_query(self, request: abci_types.RequestQuery) -> abci_types.ResponseQuery: + def send_query(self, request: abci_types.RequestQuery) -> abci_types.ResponseQuery: # type: ignore """ Sends an query request. @@ -125,8 +125,8 @@ def send_query(self, request: abci_types.RequestQuery) -> abci_types.ResponseQue return self.grpc_client.Query(request) def send_commit( - self, request: abci_types.RequestCommit - ) -> abci_types.ResponseCommit: + self, request: abci_types.RequestCommit # type: ignore + ) -> abci_types.ResponseCommit: # type: ignore """ Sends an commit request. @@ -136,8 +136,8 @@ def send_commit( return self.grpc_client.Commit(request) def send_init_chain( - self, request: abci_types.RequestInitChain - ) -> abci_types.ResponseInitChain: + self, request: abci_types.RequestInitChain # type: ignore + ) -> abci_types.ResponseInitChain: # type: ignore """ Sends an initChain request. @@ -147,8 +147,8 @@ def send_init_chain( return self.grpc_client.InitChain(request) def send_begin_block( - self, request: abci_types.RequestBeginBlock - ) -> abci_types.ResponseBeginBlock: + self, request: abci_types.RequestBeginBlock # type: ignore + ) -> abci_types.ResponseBeginBlock: # type: ignore """ Sends an beginBlock request. @@ -158,8 +158,8 @@ def send_begin_block( return self.grpc_client.BeginBlock(request) def send_end_block( - self, request: abci_types.RequestEndBlock - ) -> abci_types.ResponseEndBlock: + self, request: abci_types.RequestEndBlock # type: ignore + ) -> abci_types.ResponseEndBlock: # type: ignore """ Sends an endBlock request. @@ -169,8 +169,8 @@ def send_end_block( return self.grpc_client.EndBlock(request) def send_list_snapshots( - self, request: abci_types.RequestListSnapshots - ) -> abci_types.ResponseListSnapshots: + self, request: abci_types.RequestListSnapshots # type: ignore + ) -> abci_types.ResponseListSnapshots: # type: ignore """ Sends an listSnapshots request. @@ -180,8 +180,8 @@ def send_list_snapshots( return self.grpc_client.ListSnapshots(request) def send_offer_snapshot( - self, request: abci_types.RequestOfferSnapshot - ) -> abci_types.ResponseOfferSnapshot: + self, request: abci_types.RequestOfferSnapshot # type: ignore + ) -> abci_types.ResponseOfferSnapshot: # type: ignore """ Sends an offerSnapshot request. @@ -191,8 +191,8 @@ def send_offer_snapshot( return self.grpc_client.OfferSnapshot(request) def send_load_snapshot_chunk( - self, request: abci_types.RequestLoadSnapshotChunk - ) -> abci_types.ResponseLoadSnapshotChunk: + self, request: abci_types.RequestLoadSnapshotChunk # type: ignore + ) -> abci_types.ResponseLoadSnapshotChunk: # type: ignore """ Sends an loadSnapshotChunk request. @@ -202,8 +202,8 @@ def send_load_snapshot_chunk( return self.grpc_client.LoadSnapshotChunk(request) def send_apply_snapshot_chunk( - self, request: abci_types.RequestApplySnapshotChunk - ) -> abci_types.ResponseApplySnapshotChunk: + self, request: abci_types.RequestApplySnapshotChunk # type: ignore + ) -> abci_types.ResponseApplySnapshotChunk: # type: ignore """ Sends an applySnapshotChunk request. diff --git a/packages/valory/connections/abci/tests/test_fuzz/mock_node/channels/tcp_channel.py b/packages/valory/connections/abci/tests/test_fuzz/mock_node/channels/tcp_channel.py index 318b486a40..a28cb7ea15 100644 --- a/packages/valory/connections/abci/tests/test_fuzz/mock_node/channels/tcp_channel.py +++ b/packages/valory/connections/abci/tests/test_fuzz/mock_node/channels/tcp_channel.py @@ -122,7 +122,7 @@ def _run_loop_in_thread(loop: AbstractEventLoop) -> None: asyncio.set_event_loop(loop) loop.run_forever() - def _get_response(self) -> abci_types.Response: + def _get_response(self) -> abci_types.Response: # type: ignore """ Gets the response for a request. @@ -138,7 +138,7 @@ def _get_response(self) -> abci_types.Response: cast(AbstractEventLoop, self.loop), ) message_bytes = future.result() - message = abci_types.Response() + message = abci_types.Response() # type: ignore message.ParseFromString(message_bytes) return message @@ -151,7 +151,7 @@ def _send_data(self, data: bytes) -> None: ) future.result() - def send_info(self, request: abci_types.RequestInfo) -> abci_types.ResponseInfo: + def send_info(self, request: abci_types.RequestInfo) -> abci_types.ResponseInfo: # type: ignore """ Sends an info request. @@ -159,7 +159,7 @@ def send_info(self, request: abci_types.RequestInfo) -> abci_types.ResponseInfo: :return: ResponseInfo pb object """ - message = abci_types.Request() + message = abci_types.Request() # type: ignore message.info.CopyFrom(request) data = _TendermintABCISerializer.write_message(message) @@ -176,14 +176,14 @@ def send_info(self, request: abci_types.RequestInfo) -> abci_types.ResponseInfo: return response.info - def send_echo(self, request: abci_types.RequestEcho) -> abci_types.ResponseEcho: + def send_echo(self, request: abci_types.RequestEcho) -> abci_types.ResponseEcho: # type: ignore """ Sends an echo request. :param: request: RequestEcho pb object :return: ResponseEcho pb object """ - message = abci_types.Request() + message = abci_types.Request() # type: ignore message.echo.CopyFrom(request) data = _TendermintABCISerializer.write_message(message) @@ -200,14 +200,14 @@ def send_echo(self, request: abci_types.RequestEcho) -> abci_types.ResponseEcho: return response.echo - def send_flush(self, request: abci_types.RequestFlush) -> abci_types.ResponseFlush: + def send_flush(self, request: abci_types.RequestFlush) -> abci_types.ResponseFlush: # type: ignore """ Sends an flush request. :param: request: RequestFlush pb object :return: ResponseFlush pb object """ - message = abci_types.Request() + message = abci_types.Request() # type: ignore message.flush.CopyFrom(request) data = _TendermintABCISerializer.write_message(message) @@ -225,15 +225,15 @@ def send_flush(self, request: abci_types.RequestFlush) -> abci_types.ResponseFlu return response.flush def send_set_option( - self, request: abci_types.RequestSetOption - ) -> abci_types.ResponseSetOption: + self, request: abci_types.RequestSetOption # type: ignore + ) -> abci_types.ResponseSetOption: # type: ignore """ Sends an setOption request. :param: request: RequestSetOption pb object :return: ResponseSetOption pb object """ - message = abci_types.Request() + message = abci_types.Request() # type: ignore message.set_option.CopyFrom(request) data = _TendermintABCISerializer.write_message(message) @@ -251,15 +251,15 @@ def send_set_option( return response.set_option def send_deliver_tx( - self, request: abci_types.RequestDeliverTx - ) -> abci_types.ResponseDeliverTx: + self, request: abci_types.RequestDeliverTx # type: ignore + ) -> abci_types.ResponseDeliverTx: # type: ignore """ Sends an deliverTx request. :param: request: RequestDeliverTx pb object :return: ResponseDeliverTx pb object """ - message = abci_types.Request() + message = abci_types.Request() # type: ignore message.deliver_tx.CopyFrom(request) data = _TendermintABCISerializer.write_message(message) @@ -277,15 +277,15 @@ def send_deliver_tx( return response.deliver_tx def send_check_tx( - self, request: abci_types.RequestCheckTx - ) -> abci_types.ResponseCheckTx: + self, request: abci_types.RequestCheckTx # type: ignore + ) -> abci_types.ResponseCheckTx: # type: ignore """ Sends an checkTx request. :param: request: RequestCheckTx pb object :return: ResponseCheckTx pb object """ - message = abci_types.Request() + message = abci_types.Request() # type: ignore message.check_tx.CopyFrom(request) data = _TendermintABCISerializer.write_message(message) @@ -302,14 +302,14 @@ def send_check_tx( return response.check_tx - def send_query(self, request: abci_types.RequestQuery) -> abci_types.ResponseQuery: + def send_query(self, request: abci_types.RequestQuery) -> abci_types.ResponseQuery: # type: ignore """ Sends an query request. :param: request: RequestQuery pb object :return: ResponseQuery pb object """ - message = abci_types.Request() + message = abci_types.Request() # type: ignore message.query.CopyFrom(request) data = _TendermintABCISerializer.write_message(message) @@ -327,15 +327,15 @@ def send_query(self, request: abci_types.RequestQuery) -> abci_types.ResponseQue return response.query def send_commit( - self, request: abci_types.RequestCommit - ) -> abci_types.ResponseCommit: + self, request: abci_types.RequestCommit # type: ignore + ) -> abci_types.ResponseCommit: # type: ignore """ Sends an commit request. :param: request: RequestCommit pb object :return: ResponseCommit pb object """ - message = abci_types.Request() + message = abci_types.Request() # type: ignore message.commit.CopyFrom(request) data = _TendermintABCISerializer.write_message(message) @@ -353,15 +353,15 @@ def send_commit( return response.commit def send_init_chain( - self, request: abci_types.RequestInitChain - ) -> abci_types.ResponseInitChain: + self, request: abci_types.RequestInitChain # type: ignore + ) -> abci_types.ResponseInitChain: # type: ignore """ Sends an initChain request. :param: request: RequestInitChain pb object :return: ResponseInitChain pb object """ - message = abci_types.Request() + message = abci_types.Request() # type: ignore message.init_chain.CopyFrom(request) data = _TendermintABCISerializer.write_message(message) @@ -379,15 +379,15 @@ def send_init_chain( return response.init_chain def send_begin_block( - self, request: abci_types.RequestBeginBlock - ) -> abci_types.ResponseBeginBlock: + self, request: abci_types.RequestBeginBlock # type: ignore + ) -> abci_types.ResponseBeginBlock: # type: ignore """ Sends an beginBlock request. :param: request: RequestBeginBlock pb object :return: ResponseBeginBlock pb object """ - message = abci_types.Request() + message = abci_types.Request() # type: ignore message.begin_block.CopyFrom(request) data = _TendermintABCISerializer.write_message(message) @@ -405,15 +405,15 @@ def send_begin_block( return response.begin_block def send_end_block( - self, request: abci_types.RequestEndBlock - ) -> abci_types.ResponseEndBlock: + self, request: abci_types.RequestEndBlock # type: ignore + ) -> abci_types.ResponseEndBlock: # type: ignore """ Sends an endBlock request. :param: request: RequestEndBlock pb object :return: ResponseEndBlock pb object """ - message = abci_types.Request() + message = abci_types.Request() # type: ignore message.end_block.CopyFrom(request) data = _TendermintABCISerializer.write_message(message) @@ -431,15 +431,15 @@ def send_end_block( return response.end_block def send_list_snapshots( - self, request: abci_types.RequestListSnapshots - ) -> abci_types.ResponseListSnapshots: + self, request: abci_types.RequestListSnapshots # type: ignore + ) -> abci_types.ResponseListSnapshots: # type: ignore """ Sends an listSnapshots request. :param: request: RequestListSnapshots pb object :return: ResponseListSnapshots pb object """ - message = abci_types.Request() + message = abci_types.Request() # type: ignore message.list_snapshots.CopyFrom(request) data = _TendermintABCISerializer.write_message(message) @@ -457,15 +457,15 @@ def send_list_snapshots( return response.list_snapshots def send_offer_snapshot( - self, request: abci_types.RequestOfferSnapshot - ) -> abci_types.ResponseOfferSnapshot: + self, request: abci_types.RequestOfferSnapshot # type: ignore + ) -> abci_types.ResponseOfferSnapshot: # type: ignore """ Sends an offerSnapshot request. :param: request: RequestOfferSnapshot pb object :return: ResponseOfferSnapshot pb object """ - message = abci_types.Request() + message = abci_types.Request() # type: ignore message.offer_snapshot.CopyFrom(request) data = _TendermintABCISerializer.write_message(message) @@ -483,15 +483,15 @@ def send_offer_snapshot( return response.offer_snapshot def send_load_snapshot_chunk( - self, request: abci_types.RequestLoadSnapshotChunk - ) -> abci_types.ResponseLoadSnapshotChunk: + self, request: abci_types.RequestLoadSnapshotChunk # type: ignore + ) -> abci_types.ResponseLoadSnapshotChunk: # type: ignore """ Sends an loadSnapshotChunk request. :param: request: RequestLoadSnapshotChunk pb object :return: ResponseLoadSnapshotChunk pb object """ - message = abci_types.Request() + message = abci_types.Request() # type: ignore message.load_snapshot_chunk.CopyFrom(request) data = _TendermintABCISerializer.write_message(message) @@ -509,15 +509,15 @@ def send_load_snapshot_chunk( return response.load_snapshot_chunk def send_apply_snapshot_chunk( - self, request: abci_types.RequestApplySnapshotChunk - ) -> abci_types.ResponseApplySnapshotChunk: + self, request: abci_types.RequestApplySnapshotChunk # type: ignore + ) -> abci_types.ResponseApplySnapshotChunk: # type: ignore """ Sends an applySnapshotChunk request. :param: request: RequestApplySnapshotChunk pb object :return: ResponseApplySnapshotChunk pb object """ - message = abci_types.Request() + message = abci_types.Request() # type: ignore message.apply_snapshot_chunk.CopyFrom(request) data = _TendermintABCISerializer.write_message(message) diff --git a/packages/valory/connections/abci/tests/test_fuzz/mock_node/node.py b/packages/valory/connections/abci/tests/test_fuzz/mock_node/node.py index 6c87b6d6ee..3c5bb3f87c 100644 --- a/packages/valory/connections/abci/tests/test_fuzz/mock_node/node.py +++ b/packages/valory/connections/abci/tests/test_fuzz/mock_node/node.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- # ------------------------------------------------------------------------------ # -# Copyright 2021-2022 Valory AG +# Copyright 2021-2023 Valory AG # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -71,7 +71,7 @@ def disconnect(self) -> None: self.channel.disconnect() def info(self, version: str, block_version: int, p2p_version: int) -> bool: - request = abci_types.RequestInfo() + request = abci_types.RequestInfo() # type: ignore request.version = version request.block_version = block_version request.p2p_version = p2p_version @@ -87,7 +87,7 @@ def info(self, version: str, block_version: int, p2p_version: int) -> bool: return True def echo(self, message: str) -> bool: - request = abci_types.RequestEcho() + request = abci_types.RequestEcho() # type: ignore request.message = message self.logger.info(f"Calling echo with message={message}") @@ -98,7 +98,7 @@ def echo(self, message: str) -> bool: return True def flush(self) -> bool: - request = abci_types.RequestFlush() + request = abci_types.RequestFlush() # type: ignore self.logger.info("Sending flush req") @@ -109,7 +109,7 @@ def flush(self) -> bool: return True def set_option(self, key: str, value: str) -> bool: - request = abci_types.RequestSetOption() + request = abci_types.RequestSetOption() # type: ignore request.key = key request.value = value @@ -122,7 +122,7 @@ def set_option(self, key: str, value: str) -> bool: return True def deliver_tx(self, tx: bytes) -> bool: - request = abci_types.RequestDeliverTx() + request = abci_types.RequestDeliverTx() # type: ignore request.tx = tx self.logger.info(f"Calling deliver_tx with tx={tx!r}") @@ -134,7 +134,7 @@ def deliver_tx(self, tx: bytes) -> bool: return True def check_tx(self, tx: bytes, is_new_check: bool) -> bool: - request = abci_types.RequestCheckTx() + request = abci_types.RequestCheckTx() # type: ignore request.tx = tx request.type = 1 if is_new_check else 0 @@ -147,7 +147,7 @@ def check_tx(self, tx: bytes, is_new_check: bool) -> bool: return response def query(self, data: bytes, path: str, height: int, prove: bool) -> bool: - request = abci_types.RequestQuery() + request = abci_types.RequestQuery() # type: ignore request.data = data request.path = path request.height = height @@ -164,7 +164,7 @@ def query(self, data: bytes, path: str, height: int, prove: bool) -> bool: return True def commit(self) -> bool: - request = abci_types.RequestCommit() + request = abci_types.RequestCommit() # type: ignore self.logger.info("Calling commit") @@ -192,7 +192,7 @@ def init_chain( app_state_bytes: bytes, initial_height: int, ) -> bool: - request = abci_types.RequestInitChain() + request = abci_types.RequestInitChain() # type: ignore timestamp = timestamp_pb2.Timestamp() Timestamp.encode(timestamp, Timestamp(time_seconds, time_nanos)) @@ -207,7 +207,7 @@ def init_chain( ) validator_params = ValidatorParams(pub_key_types) version_params = VersionParams(app_version) - consensus_params = abci_types.ConsensusParams() + consensus_params = abci_types.ConsensusParams() # type: ignore ConsensusParams.encode( consensus_params, ConsensusParams( @@ -230,8 +230,8 @@ def init_chain( validator_updates_pb = [] for validator_update_object in validator_updates: - validator_update_protobuf_object = abci_types.ValidatorUpdate() - pub_key = keys_types.PublicKey() + validator_update_protobuf_object = abci_types.ValidatorUpdate() # type: ignore + pub_key = keys_types.PublicKey() # type: ignore PublicKey.encode(pub_key, validator_update_object.pub_key) validator_update_protobuf_object.power = validator_update_object.power @@ -302,15 +302,15 @@ def begin_block( evidence_time_nanos: List[int], evidence_total_voting_power: List[int], ) -> bool: - consensus_version = version_type.Consensus() + consensus_version = version_type.Consensus() # type: ignore consensus_version.block = consen_ver_block consensus_version.app = consen_ver_app - part_set_header = tendermint_types.PartSetHeader() + part_set_header = tendermint_types.PartSetHeader() # type: ignore part_set_header.total = next_validators_part_header_total part_set_header.hash = next_validators_part_header_hash - block_id = tendermint_types.BlockID() + block_id = tendermint_types.BlockID() # type: ignore block_id.hash = last_block_id_hash block_id.part_set_header.CopyFrom(part_set_header) @@ -318,7 +318,7 @@ def begin_block( time.seconds = time_seconds time.nanos = time_nanos - header = tendermint_types.Header() + header = tendermint_types.Header() # type: ignore header.version.CopyFrom(consensus_version) header.chain_id = chain_id header.height = height @@ -342,17 +342,17 @@ def begin_block( vote_infos = [] for i in range(last_commit_info_votes.__len__()): - validator = abci_types.Validator() + validator = abci_types.Validator() # type: ignore validator.address = last_commit_info_votes[i][0] validator.power = last_commit_info_votes[i][1] - vote_info = abci_types.VoteInfo() + vote_info = abci_types.VoteInfo() # type: ignore vote_info.validator.CopyFrom(validator) vote_info.signed_last_block = last_commit_info_signed_last_block[i] vote_infos.append(vote_info) - last_commit_info = abci_types.LastCommitInfo() + last_commit_info = abci_types.LastCommitInfo() # type: ignore last_commit_info.round = last_commit_round last_commit_info.votes.extend(vote_infos) @@ -373,7 +373,7 @@ def begin_block( evidences = [] for i in range(evidence_type.__len__()): - validator = abci_types.Validator() + validator = abci_types.Validator() # type: ignore validator.address = evidence_validator_address[i] validator.power = evidence_validator_power[i] @@ -381,7 +381,7 @@ def begin_block( time.seconds = evidence_time_seconds[i] time.nanos = evidence_time_nanos[i] - evidence = abci_types.Evidence() + evidence = abci_types.Evidence() # type: ignore evidence.type = evidence_type[i] % 3 evidence.height = evidence_height[i] evidence.total_voting_power = evidence_total_voting_power[i] @@ -390,7 +390,7 @@ def begin_block( evidences.append(evidence) - request = abci_types.RequestBeginBlock() + request = abci_types.RequestBeginBlock() # type: ignore request.hash = hash_ request.header.CopyFrom(header) request.last_commit_info.CopyFrom(last_commit_info) @@ -438,7 +438,7 @@ def begin_block( return True def end_block(self, height: int) -> bool: - request = abci_types.RequestEndBlock() + request = abci_types.RequestEndBlock() # type: ignore request.height = height self.logger.info(f"Calling end_block height={height}") @@ -450,7 +450,7 @@ def end_block(self, height: int) -> bool: return response def list_snapshots(self) -> bool: - request = abci_types.RequestListSnapshots() + request = abci_types.RequestListSnapshots() # type: ignore self.logger.info("Calling list snapshots") @@ -469,10 +469,10 @@ def offer_snapshot( metadata: bytes, app_hash: bytes, ) -> bool: - snapshot = abci_types.Snapshot() + snapshot = abci_types.Snapshot() # type: ignore Snapshot.encode(snapshot, Snapshot(height, format_, chunks, hash_, metadata)) - request = abci_types.RequestOfferSnapshot() + request = abci_types.RequestOfferSnapshot() # type: ignore request.snapshot.CopyFrom(snapshot) request.app_hash = app_hash @@ -488,7 +488,7 @@ def offer_snapshot( return response def load_snapshot_chunk(self, height: int, format_: int, chunk: int) -> bool: - request = abci_types.RequestLoadSnapshotChunk() + request = abci_types.RequestLoadSnapshotChunk() # type: ignore request.height = height request.format = format_ request.chunk = chunk @@ -504,7 +504,7 @@ def load_snapshot_chunk(self, height: int, format_: int, chunk: int) -> bool: return response def apply_snapshot_chunk(self, index: int, chunk: bytes, sender: str) -> bool: - request = abci_types.RequestApplySnapshotChunk() + request = abci_types.RequestApplySnapshotChunk() # type: ignore request.index = index request.chunk = chunk request.sender = sender diff --git a/packages/valory/connections/abci/tests/test_fuzz/test_fuzz.py b/packages/valory/connections/abci/tests/test_fuzz/test_fuzz.py index 2bfb95328a..02333a39c3 100644 --- a/packages/valory/connections/abci/tests/test_fuzz/test_fuzz.py +++ b/packages/valory/connections/abci/tests/test_fuzz/test_fuzz.py @@ -22,7 +22,7 @@ from hypothesis import settings -from packages.valory.connections.abci import CI +from packages.valory.connections.abci.tests import CI from packages.valory.connections.abci.tests.test_fuzz.base import BaseFuzzyTests from packages.valory.connections.abci.tests.test_fuzz.mock_node.channels.grpc_channel import ( GrpcChannel, diff --git a/packages/valory/connections/ipfs/connection.yaml b/packages/valory/connections/ipfs/connection.yaml index 904845a6de..429681c4f0 100644 --- a/packages/valory/connections/ipfs/connection.yaml +++ b/packages/valory/connections/ipfs/connection.yaml @@ -14,7 +14,7 @@ fingerprint: fingerprint_ignore_patterns: [] connections: [] protocols: -- valory/ipfs:0.1.0:bafybeic72ncgqbzoz2guj4p4yjqulid7mv6yroeh65hxznloamoveeg7hq +- valory/ipfs:0.1.0:bafybeiedxeismnx3k5ty4mvvhlqideixlhqmi5mtcki4lxqfa7uqh7p33u class_name: IpfsConnection config: ipfs_domain: null @@ -24,7 +24,7 @@ dependencies: ipfshttpclient: version: ==0.8.0a2 open-aea-cli-ipfs: - version: ==1.32.0 + version: ==1.43.0.post2 requests: version: ==2.28.1 is_abstract: false diff --git a/packages/valory/contracts/agent_registry/contract.py b/packages/valory/contracts/agent_registry/contract.py index 4af182b252..b7d4984ff6 100644 --- a/packages/valory/contracts/agent_registry/contract.py +++ b/packages/valory/contracts/agent_registry/contract.py @@ -20,7 +20,7 @@ """This module contains the class to connect to the Service Registry contract.""" import logging -from typing import Any, Optional, cast +from typing import Any, Dict, Optional from aea.common import JSONLike from aea.configurations.base import PublicId @@ -65,47 +65,67 @@ def get_state( raise NotImplementedError # pragma: nocover @classmethod - def get_token_uri( + def get_events( # pragma: nocover cls, ledger_api: LedgerApi, contract_address: str, - token_id: int, - ) -> str: - """Returns `CreateUnit` event filter.""" - + event: str, + receipt: JSONLike, + ) -> Dict: + """Process receipt for events.""" contract_interface = cls.get_instance( ledger_api=ledger_api, contract_address=contract_address, ) - return contract_interface.functions.tokenURI(token_id).call() + Event = getattr(contract_interface.events, event, None) + if Event is None: + return {"events": []} + return {"events": Event().process_receipt(receipt)} @classmethod - def filter_token_id_from_emitted_events( + def get_create_events( # pragma: nocover cls, ledger_api: LedgerApi, contract_address: str, - metadata_hash: str, + receipt: JSONLike, ) -> Optional[int]: """Returns `CreateUnit` event filter.""" + contract_interface = cls.get_instance( + ledger_api=ledger_api, + contract_address=contract_address, + ) + return contract_interface.events.CreateUnit().process_receipt(receipt) + @classmethod + def get_update_hash_events( # pragma: nocover + cls, + ledger_api: LedgerApi, + contract_address: str, + receipt: JSONLike, + ) -> Optional[int]: + """Returns `CreateUnit` event filter.""" contract_interface = cls.get_instance( ledger_api=ledger_api, contract_address=contract_address, ) + return contract_interface.events.UpdateUnitHash().process_receipt(receipt) - events = contract_interface.events.CreateUnit.createFilter( - fromBlock="latest" - ).get_all_entries() - - for event in events: - event_args = event["args"] - if event_args["uType"] == AGENT_UNIT_TYPE: - hash_bytes32 = cast(bytes, event_args["unitHash"]).hex() - unit_hash_bytes = UNIT_HASH_PREFIX.format( - metadata_hash=hash_bytes32 - ).encode() - metadata_hash_bytes = ledger_api.api.toBytes(text=metadata_hash) - if unit_hash_bytes == metadata_hash_bytes: - return cast(int, event_args["unitId"]) - - return None + @classmethod + def get_token_uri( + cls, + ledger_api: LedgerApi, + contract_address: str, + token_id: int, + ) -> str: + """Returns the latest metadata URI for a component.""" + contract_interface = cls.get_instance( + ledger_api=ledger_api, + contract_address=contract_address, + ) + _, hash_updates = contract_interface.functions.getUpdatedHashes(token_id).call() + if len(hash_updates) > 0: # pragma: nocover + *_, latest_hash = hash_updates + uri = f"https://gateway.autonolas.tech/ipfs/f01701220{latest_hash.hex()}" + else: + uri = contract_interface.functions.tokenURI(token_id).call() + return uri diff --git a/packages/valory/contracts/agent_registry/contract.yaml b/packages/valory/contracts/agent_registry/contract.yaml index f9b48e77b7..b302426818 100644 --- a/packages/valory/contracts/agent_registry/contract.yaml +++ b/packages/valory/contracts/agent_registry/contract.yaml @@ -8,13 +8,12 @@ aea_version: '>=1.0.0, <2.0.0' fingerprint: __init__.py: bafybeiaaoxkui6cjj52avj3xbriazrwdg6bcfqxmukkw7emwc2q4hbdfdi build/AgentRegistry.json: bafybeiclduduvyfzuuk762qfjig5bfvyw44ivhwj65bd4bezhjghdk4zri - contract.py: bafybeifuljjha5owzczkvhmuejfdbhe5gv2wimmkkcbtqn3df7izqdmwae + contract.py: bafybeigsb6qtcawq5hqa5vgjxbtex7dtxdr6jx2y4ffxcihxc675cwxml4 tests/__init__.py: bafybeig6vb3j7xuemr25f5uapvhyuo4hlk3rbfiq7kfxg4f5gfz6oc6tte - tests/test_contract.py: bafybeiblqjct2bikktwve4skpz3elanl7rt3jbguwxqtvcdxetefm3v4sa + tests/test_contract.py: bafybeichmcfjtqyv3435grfl54ijeelgoe4owoqh3xeutcjodexbjl6f74 fingerprint_ignore_patterns: [] contracts: [] class_name: AgentRegistryContract contract_interface_paths: ethereum: build/AgentRegistry.json - ethereum_hwi: build/AgentRegistry.json dependencies: {} diff --git a/packages/valory/contracts/agent_registry/tests/test_contract.py b/packages/valory/contracts/agent_registry/tests/test_contract.py index 794253c740..b18e65194f 100644 --- a/packages/valory/contracts/agent_registry/tests/test_contract.py +++ b/packages/valory/contracts/agent_registry/tests/test_contract.py @@ -20,17 +20,12 @@ """Test for contract module.""" from pathlib import Path -from unittest import mock from aea_test_autonomy.base_test_classes.contracts import BaseRegistriesContractsTest from aea_test_autonomy.docker.base import skip_docker_tests from aea_test_autonomy.docker.registries import AGENT_REGISTRY -from packages.valory.contracts.agent_registry.contract import ( - AGENT_UNIT_TYPE, - AgentRegistryContract, - UNIT_HASH_PREFIX, -) +from packages.valory.contracts.agent_registry.contract import AgentRegistryContract PACKAGE_DIR = Path(__file__).parent.parent @@ -57,60 +52,3 @@ def test_get_token_uri(self) -> None: token_uri == "https://gateway.autonolas.tech/ipfs/f01701220985b4c36158b51f8a865faceff8141dbc0989c349a1a41ba1e2ac8e5b24536b2" # nosec ) - - def test_filter_token_id_from_emitted_events(self) -> None: - """Test `filter_token_id_from_emitted_events` method""" - - dummy_hash = b"dummy_hash" - expected_hash = UNIT_HASH_PREFIX.format(metadata_hash=dummy_hash.hex()) - - with mock.patch.object( - AgentRegistryContract, - "get_instance", - return_value=mock.MagicMock( - events=mock.MagicMock( - CreateUnit=mock.MagicMock( - createFilter=lambda **_: mock.MagicMock( - get_all_entries=lambda *_: [] - ) - ) - ) - ), - ): - token_id = self.contract.filter_token_id_from_emitted_events( - ledger_api=self.ledger_api, - contract_address=self.contract_address, - metadata_hash=expected_hash, - ) - assert token_id is None - - with mock.patch.object( - AgentRegistryContract, - "get_instance", - return_value=mock.MagicMock( - events=mock.MagicMock( - CreateUnit=mock.MagicMock( - createFilter=lambda **_: mock.MagicMock( - get_all_entries=lambda *_: [ - { - "args": { - "uType": AGENT_UNIT_TYPE, - "unitHash": dummy_hash, - "unitId": 1, - } - } - ] - ) - ) - ) - ), - ), mock.patch.object( - self.ledger_api.api, "toBytes", return_value=expected_hash.encode() - ): - token_id = self.contract.filter_token_id_from_emitted_events( - ledger_api=self.ledger_api, - contract_address=self.contract_address, - metadata_hash=expected_hash, - ) - assert token_id is not None - assert token_id == 1 diff --git a/packages/valory/contracts/component_registry/contract.py b/packages/valory/contracts/component_registry/contract.py index ad220d407e..77e8ac5d0f 100644 --- a/packages/valory/contracts/component_registry/contract.py +++ b/packages/valory/contracts/component_registry/contract.py @@ -20,7 +20,7 @@ """This module contains the class to connect to the Service Registry contract.""" import logging -from typing import Any, Optional, cast +from typing import Any, Dict, Optional from aea.common import JSONLike from aea.configurations.base import PublicId @@ -65,34 +65,50 @@ def get_state( raise NotImplementedError # pragma: nocover @classmethod - def filter_token_id_from_emitted_events( + def get_events( # pragma: nocover cls, ledger_api: LedgerApi, contract_address: str, - metadata_hash: str, + event: str, + receipt: JSONLike, + ) -> Dict: + """Process receipt for events.""" + contract_interface = cls.get_instance( + ledger_api=ledger_api, + contract_address=contract_address, + ) + Event = getattr(contract_interface.events, event, None) + if Event is None: + return {"events": []} + return {"events": Event().process_receipt(receipt)} + + @classmethod + def get_create_events( + cls, + ledger_api: LedgerApi, + contract_address: str, + receipt: JSONLike, ) -> Optional[int]: """Returns `CreateUnit` event filter.""" - contract_interface = cls.get_instance( ledger_api=ledger_api, contract_address=contract_address, ) + return contract_interface.events.CreateUnit().process_receipt(receipt) - events = contract_interface.events.CreateUnit.createFilter( - fromBlock="latest" - ).get_all_entries() - for event in events: - event_args = event["args"] - if event_args["uType"] == COMPONENT_UNIT_TYPE: - hash_bytes32 = cast(bytes, event_args["unitHash"]).hex() - unit_hash_bytes = UNIT_HASH_PREFIX.format( - metadata_hash=hash_bytes32 - ).encode() - metadata_hash_bytes = ledger_api.api.toBytes(text=metadata_hash) - if unit_hash_bytes == metadata_hash_bytes: - return cast(int, event_args["unitId"]) - - return None + @classmethod + def get_update_hash_events( + cls, + ledger_api: LedgerApi, + contract_address: str, + receipt: JSONLike, + ) -> Optional[int]: + """Returns `CreateUnit` event filter.""" + contract_interface = cls.get_instance( + ledger_api=ledger_api, + contract_address=contract_address, + ) + return contract_interface.events.UpdateUnitHash().process_receipt(receipt) @classmethod def get_token_uri( @@ -101,10 +117,15 @@ def get_token_uri( contract_address: str, token_id: int, ) -> str: - """Returns `CreateUnit` event filter.""" - + """Returns the latest metadata URI for a component.""" contract_interface = cls.get_instance( ledger_api=ledger_api, contract_address=contract_address, ) - return contract_interface.functions.tokenURI(token_id).call() + _, hash_updates = contract_interface.functions.getUpdatedHashes(token_id).call() + if len(hash_updates) > 0: + *_, latest_hash = hash_updates + uri = f"https://gateway.autonolas.tech/ipfs/f01701220{latest_hash.hex()}" + else: + uri = contract_interface.functions.tokenURI(token_id).call() + return uri diff --git a/packages/valory/contracts/component_registry/contract.yaml b/packages/valory/contracts/component_registry/contract.yaml index ca858455bf..e526ab35ca 100644 --- a/packages/valory/contracts/component_registry/contract.yaml +++ b/packages/valory/contracts/component_registry/contract.yaml @@ -8,13 +8,12 @@ aea_version: '>=1.0.0, <2.0.0' fingerprint: __init__.py: bafybeihqlwkxffyqkqzzoqbm3t5caqxl75po6yk5cfjg5jp56dy47qqmv4 build/ComponentRegistry.json: bafybeicssz7csipr7lhxvro6chtd45f6iqykserv35ppjtxetpx75ouno4 - contract.py: bafybeibqa32zg3us3ht7wfsnqud7y5iefq3bqeabkt6ssd4mzjm4fhvzye + contract.py: bafybeigkfapo376gudvv3zwbkomrv73jffc2j6fidfkaxrrgfmq62wwjci tests/__init__.py: bafybeihe42ydu66tbdogfyjh3rqgnwuhglnwll47aaagjj6b3fjngrxauq - tests/test_contract.py: bafybeifz3xy64rkyfgg6fv2awh7u3cvxl3mjgrruu4xv3b6mbq7osz6hza + tests/test_contract.py: bafybeiegforxfp6iih7rp6cupzyx4v2cagqquncam6kaadpoe5tlfcmgia fingerprint_ignore_patterns: [] contracts: [] class_name: ComponentRegistryContract contract_interface_paths: ethereum: build/ComponentRegistry.json - ethereum_hwi: build/ComponentRegistry.json dependencies: {} diff --git a/packages/valory/contracts/component_registry/tests/test_contract.py b/packages/valory/contracts/component_registry/tests/test_contract.py index 6d831012f1..32bd2256af 100644 --- a/packages/valory/contracts/component_registry/tests/test_contract.py +++ b/packages/valory/contracts/component_registry/tests/test_contract.py @@ -20,16 +20,13 @@ """Test for contract module.""" from pathlib import Path -from unittest import mock from aea_test_autonomy.base_test_classes.contracts import BaseRegistriesContractsTest from aea_test_autonomy.docker.base import skip_docker_tests from aea_test_autonomy.docker.registries import COMPONENT_REGISTRY from packages.valory.contracts.component_registry.contract import ( - COMPONENT_UNIT_TYPE, ComponentRegistryContract, - UNIT_HASH_PREFIX, ) @@ -57,60 +54,3 @@ def test_get_token_uri(self) -> None: token_uri == "https://gateway.autonolas.tech/ipfs/f01701220f6da10e4468f23f9a435c6bbd3f292271823991e637a23ec8a040b2502169275" # nosec ) - - def test_filter_token_id_from_emitted_events(self) -> None: - """Test `filter_token_id_from_emitted_events` method""" - - dummy_hash = b"dummy_hash" - expected_hash = UNIT_HASH_PREFIX.format(metadata_hash=dummy_hash.hex()) - - with mock.patch.object( - ComponentRegistryContract, - "get_instance", - return_value=mock.MagicMock( - events=mock.MagicMock( - CreateUnit=mock.MagicMock( - createFilter=lambda **_: mock.MagicMock( - get_all_entries=lambda *_: [] - ) - ) - ) - ), - ): - token_id = self.contract.filter_token_id_from_emitted_events( - ledger_api=self.ledger_api, - contract_address=self.contract_address, - metadata_hash=expected_hash, - ) - assert token_id is None - - with mock.patch.object( - ComponentRegistryContract, - "get_instance", - return_value=mock.MagicMock( - events=mock.MagicMock( - CreateUnit=mock.MagicMock( - createFilter=lambda **_: mock.MagicMock( - get_all_entries=lambda *_: [ - { - "args": { - "uType": COMPONENT_UNIT_TYPE, - "unitHash": dummy_hash, - "unitId": 1, - } - } - ] - ) - ) - ) - ), - ), mock.patch.object( - self.ledger_api.api, "toBytes", return_value=expected_hash.encode() - ): - token_id = self.contract.filter_token_id_from_emitted_events( - ledger_api=self.ledger_api, - contract_address=self.contract_address, - metadata_hash=expected_hash, - ) - assert token_id is not None - assert token_id == 1 diff --git a/packages/valory/contracts/erc20/__init__.py b/packages/valory/contracts/erc20/__init__.py new file mode 100644 index 0000000000..9e8332df28 --- /dev/null +++ b/packages/valory/contracts/erc20/__init__.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# ------------------------------------------------------------------------------ +# +# Copyright 2023 valory +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# ------------------------------------------------------------------------------ + +"""This module contains the support resources for the scaffold contract.""" diff --git a/packages/valory/contracts/erc20/build/ERC20.json b/packages/valory/contracts/erc20/build/ERC20.json new file mode 100644 index 0000000000..0aadef47cd --- /dev/null +++ b/packages/valory/contracts/erc20/build/ERC20.json @@ -0,0 +1,331 @@ +{ + "_format": "hh-sol-artifact-1", + "contractName": "ERC20Token", + "sourceName": "contracts/test/ERC20Token.sol", + "abi": [ + { + "inputs": [], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event" + }, + { + "inputs": [], + "name": "DOMAIN_SEPARATOR", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + }, + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "decimals", + "outputs": [ + { + "internalType": "uint8", + "name": "", + "type": "uint8" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "mint", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "name", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "nonces", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + }, + { + "internalType": "uint8", + "name": "v", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "r", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "s", + "type": "bytes32" + } + ], + "name": "permit", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "symbol", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + } + ], + "bytecode": "0x60e06040523480156200001157600080fd5b506040518060400160405280601381526020017f45524332302067656e6572696320746f6b656e000000000000000000000000008152506040518060400160405280600a81526020016922a92199182a37b5b2b760b11b815250601282600090816200007e9190620001f1565b5060016200008d8382620001f1565b5060ff81166080524660a052620000a3620000b0565b60c052506200033b915050565b60007f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f6000604051620000e49190620002bd565b6040805191829003822060208301939093528101919091527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608201524660808201523060a082015260c00160405160208183030381529060405280519060200120905090565b634e487b7160e01b600052604160045260246000fd5b600181811c908216806200017757607f821691505b6020821081036200019857634e487b7160e01b600052602260045260246000fd5b50919050565b601f821115620001ec57600081815260208120601f850160051c81016020861015620001c75750805b601f850160051c820191505b81811015620001e857828155600101620001d3565b5050505b505050565b81516001600160401b038111156200020d576200020d6200014c565b62000225816200021e845462000162565b846200019e565b602080601f8311600181146200025d5760008415620002445750858301515b600019600386901b1c1916600185901b178555620001e8565b600085815260208120601f198616915b828110156200028e578886015182559484019460019091019084016200026d565b5085821015620002ad5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6000808354620002cd8162000162565b60018281168015620002e85760018114620002fe576200032f565b60ff19841687528215158302870194506200032f565b8760005260208060002060005b85811015620003265781548a8201529084019082016200030b565b50505082870194505b50929695505050505050565b60805160a05160c051610b596200036b60003960006104640152600061042f015260006101540152610b596000f3fe608060405234801561001057600080fd5b50600436106100df5760003560e01c806340c10f191161008c57806395d89b411161006657806395d89b41146101e5578063a9059cbb146101ed578063d505accf14610200578063dd62ed3e1461021357600080fd5b806340c10f191461019057806370a08231146101a55780637ecebe00146101c557600080fd5b806323b872dd116100bd57806323b872dd1461013c578063313ce5671461014f5780633644e5151461018857600080fd5b806306fdde03146100e4578063095ea7b31461010257806318160ddd14610125575b600080fd5b6100ec61023e565b6040516100f99190610876565b60405180910390f35b6101156101103660046108e0565b6102cc565b60405190151581526020016100f9565b61012e60025481565b6040519081526020016100f9565b61011561014a36600461090a565b610339565b6101767f000000000000000000000000000000000000000000000000000000000000000081565b60405160ff90911681526020016100f9565b61012e61042b565b6101a361019e3660046108e0565b610486565b005b61012e6101b3366004610946565b60036020526000908152604090205481565b61012e6101d3366004610946565b60056020526000908152604090205481565b6100ec610494565b6101156101fb3660046108e0565b6104a1565b6101a361020e366004610968565b610519565b61012e6102213660046109db565b600460209081526000928352604080842090915290825290205481565b6000805461024b90610a0e565b80601f016020809104026020016040519081016040528092919081815260200182805461027790610a0e565b80156102c45780601f10610299576101008083540402835291602001916102c4565b820191906000526020600020905b8154815290600101906020018083116102a757829003601f168201915b505050505081565b3360008181526004602090815260408083206001600160a01b038716808552925280832085905551919290917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925906103279086815260200190565b60405180910390a35060015b92915050565b6001600160a01b03831660009081526004602090815260408083203384529091528120546000198114610395576103708382610a5e565b6001600160a01b03861660009081526004602090815260408083203384529091529020555b6001600160a01b038516600090815260036020526040812080548592906103bd908490610a5e565b90915550506001600160a01b03808516600081815260036020526040908190208054870190555190918716907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef906104189087815260200190565b60405180910390a3506001949350505050565b60007f000000000000000000000000000000000000000000000000000000000000000046146104615761045c610771565b905090565b507f000000000000000000000000000000000000000000000000000000000000000090565b610490828261080b565b5050565b6001805461024b90610a0e565b336000908152600360205260408120805483919083906104c2908490610a5e565b90915550506001600160a01b038316600081815260036020526040908190208054850190555133907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef906103279086815260200190565b4284101561056e5760405162461bcd60e51b815260206004820152601760248201527f5045524d49545f444541444c494e455f4558504952454400000000000000000060448201526064015b60405180910390fd5b6000600161057a61042b565b6001600160a01b038a811660008181526005602090815260409182902080546001810190915582517f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c98184015280840194909452938d166060840152608083018c905260a083019390935260c08083018b90528151808403909101815260e08301909152805192019190912061190160f01b6101008301526101028201929092526101228101919091526101420160408051601f198184030181528282528051602091820120600084529083018083525260ff871690820152606081018590526080810184905260a0016020604051602081039080840390855afa158015610686573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038116158015906106bc5750876001600160a01b0316816001600160a01b0316145b6107085760405162461bcd60e51b815260206004820152600e60248201527f494e56414c49445f5349474e45520000000000000000000000000000000000006044820152606401610565565b6001600160a01b0390811660009081526004602090815260408083208a8516808552908352928190208990555188815291928a16917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a350505050505050565b60007f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60006040516107a39190610a71565b6040805191829003822060208301939093528101919091527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608201524660808201523060a082015260c00160405160208183030381529060405280519060200120905090565b806002600082825461081d9190610b10565b90915550506001600160a01b0382166000818152600360209081526040808320805486019055518481527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a35050565b600060208083528351808285015260005b818110156108a357858101830151858201604001528201610887565b506000604082860101526040601f19601f8301168501019250505092915050565b80356001600160a01b03811681146108db57600080fd5b919050565b600080604083850312156108f357600080fd5b6108fc836108c4565b946020939093013593505050565b60008060006060848603121561091f57600080fd5b610928846108c4565b9250610936602085016108c4565b9150604084013590509250925092565b60006020828403121561095857600080fd5b610961826108c4565b9392505050565b600080600080600080600060e0888a03121561098357600080fd5b61098c886108c4565b965061099a602089016108c4565b95506040880135945060608801359350608088013560ff811681146109be57600080fd5b9699959850939692959460a0840135945060c09093013592915050565b600080604083850312156109ee57600080fd5b6109f7836108c4565b9150610a05602084016108c4565b90509250929050565b600181811c90821680610a2257607f821691505b602082108103610a4257634e487b7160e01b600052602260045260246000fd5b50919050565b634e487b7160e01b600052601160045260246000fd5b8181038181111561033357610333610a48565b600080835481600182811c915080831680610a8d57607f831692505b60208084108203610aac57634e487b7160e01b86526022600452602486fd5b818015610ac05760018114610ad557610b02565b60ff1986168952841515850289019650610b02565b60008a81526020902060005b86811015610afa5781548b820152908501908301610ae1565b505084890196505b509498975050505050505050565b8082018082111561033357610333610a4856fea26469706673582212202327402c13d046e26ed7e2543cc5f5c252ae66602673c3505baba747841c0ac964736f6c63430008130033", + "deployedBytecode": "0x608060405234801561001057600080fd5b50600436106100df5760003560e01c806340c10f191161008c57806395d89b411161006657806395d89b41146101e5578063a9059cbb146101ed578063d505accf14610200578063dd62ed3e1461021357600080fd5b806340c10f191461019057806370a08231146101a55780637ecebe00146101c557600080fd5b806323b872dd116100bd57806323b872dd1461013c578063313ce5671461014f5780633644e5151461018857600080fd5b806306fdde03146100e4578063095ea7b31461010257806318160ddd14610125575b600080fd5b6100ec61023e565b6040516100f99190610876565b60405180910390f35b6101156101103660046108e0565b6102cc565b60405190151581526020016100f9565b61012e60025481565b6040519081526020016100f9565b61011561014a36600461090a565b610339565b6101767f000000000000000000000000000000000000000000000000000000000000000081565b60405160ff90911681526020016100f9565b61012e61042b565b6101a361019e3660046108e0565b610486565b005b61012e6101b3366004610946565b60036020526000908152604090205481565b61012e6101d3366004610946565b60056020526000908152604090205481565b6100ec610494565b6101156101fb3660046108e0565b6104a1565b6101a361020e366004610968565b610519565b61012e6102213660046109db565b600460209081526000928352604080842090915290825290205481565b6000805461024b90610a0e565b80601f016020809104026020016040519081016040528092919081815260200182805461027790610a0e565b80156102c45780601f10610299576101008083540402835291602001916102c4565b820191906000526020600020905b8154815290600101906020018083116102a757829003601f168201915b505050505081565b3360008181526004602090815260408083206001600160a01b038716808552925280832085905551919290917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925906103279086815260200190565b60405180910390a35060015b92915050565b6001600160a01b03831660009081526004602090815260408083203384529091528120546000198114610395576103708382610a5e565b6001600160a01b03861660009081526004602090815260408083203384529091529020555b6001600160a01b038516600090815260036020526040812080548592906103bd908490610a5e565b90915550506001600160a01b03808516600081815260036020526040908190208054870190555190918716907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef906104189087815260200190565b60405180910390a3506001949350505050565b60007f000000000000000000000000000000000000000000000000000000000000000046146104615761045c610771565b905090565b507f000000000000000000000000000000000000000000000000000000000000000090565b610490828261080b565b5050565b6001805461024b90610a0e565b336000908152600360205260408120805483919083906104c2908490610a5e565b90915550506001600160a01b038316600081815260036020526040908190208054850190555133907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef906103279086815260200190565b4284101561056e5760405162461bcd60e51b815260206004820152601760248201527f5045524d49545f444541444c494e455f4558504952454400000000000000000060448201526064015b60405180910390fd5b6000600161057a61042b565b6001600160a01b038a811660008181526005602090815260409182902080546001810190915582517f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c98184015280840194909452938d166060840152608083018c905260a083019390935260c08083018b90528151808403909101815260e08301909152805192019190912061190160f01b6101008301526101028201929092526101228101919091526101420160408051601f198184030181528282528051602091820120600084529083018083525260ff871690820152606081018590526080810184905260a0016020604051602081039080840390855afa158015610686573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038116158015906106bc5750876001600160a01b0316816001600160a01b0316145b6107085760405162461bcd60e51b815260206004820152600e60248201527f494e56414c49445f5349474e45520000000000000000000000000000000000006044820152606401610565565b6001600160a01b0390811660009081526004602090815260408083208a8516808552908352928190208990555188815291928a16917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a350505050505050565b60007f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60006040516107a39190610a71565b6040805191829003822060208301939093528101919091527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608201524660808201523060a082015260c00160405160208183030381529060405280519060200120905090565b806002600082825461081d9190610b10565b90915550506001600160a01b0382166000818152600360209081526040808320805486019055518481527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a35050565b600060208083528351808285015260005b818110156108a357858101830151858201604001528201610887565b506000604082860101526040601f19601f8301168501019250505092915050565b80356001600160a01b03811681146108db57600080fd5b919050565b600080604083850312156108f357600080fd5b6108fc836108c4565b946020939093013593505050565b60008060006060848603121561091f57600080fd5b610928846108c4565b9250610936602085016108c4565b9150604084013590509250925092565b60006020828403121561095857600080fd5b610961826108c4565b9392505050565b600080600080600080600060e0888a03121561098357600080fd5b61098c886108c4565b965061099a602089016108c4565b95506040880135945060608801359350608088013560ff811681146109be57600080fd5b9699959850939692959460a0840135945060c09093013592915050565b600080604083850312156109ee57600080fd5b6109f7836108c4565b9150610a05602084016108c4565b90509250929050565b600181811c90821680610a2257607f821691505b602082108103610a4257634e487b7160e01b600052602260045260246000fd5b50919050565b634e487b7160e01b600052601160045260246000fd5b8181038181111561033357610333610a48565b600080835481600182811c915080831680610a8d57607f831692505b60208084108203610aac57634e487b7160e01b86526022600452602486fd5b818015610ac05760018114610ad557610b02565b60ff1986168952841515850289019650610b02565b60008a81526020902060005b86811015610afa5781548b820152908501908301610ae1565b505084890196505b509498975050505050505050565b8082018082111561033357610333610a4856fea26469706673582212202327402c13d046e26ed7e2543cc5f5c252ae66602673c3505baba747841c0ac964736f6c63430008130033", + "linkReferences": {}, + "deployedLinkReferences": {} +} \ No newline at end of file diff --git a/packages/valory/contracts/erc20/contract.py b/packages/valory/contracts/erc20/contract.py new file mode 100644 index 0000000000..356ed93cee --- /dev/null +++ b/packages/valory/contracts/erc20/contract.py @@ -0,0 +1,130 @@ +# -*- coding: utf-8 -*- +# ------------------------------------------------------------------------------ +# +# Copyright 2023 valory +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# ------------------------------------------------------------------------------ + +"""This module contains the scaffold contract definition.""" + +from typing import Any + +from aea.common import JSONLike +from aea.configurations.base import PublicId +from aea.contracts.base import Contract +from aea.crypto.base import LedgerApi + + +class ERC20TokenContract(Contract): + """ERC20 token contract.""" + + contract_id = PublicId.from_str("valory/erc20:0.1.0") + + @classmethod + def get_raw_transaction( + cls, ledger_api: LedgerApi, contract_address: str, **kwargs: Any + ) -> JSONLike: + """ + Handler method for the 'GET_RAW_TRANSACTION' requests. + + Implement this method in the sub class if you want + to handle the contract requests manually. + + :param ledger_api: the ledger apis. + :param contract_address: the contract address. + :param kwargs: the keyword arguments. + :return: the tx # noqa: DAR202 + """ + raise NotImplementedError + + @classmethod + def get_raw_message( + cls, ledger_api: LedgerApi, contract_address: str, **kwargs: Any + ) -> bytes: + """ + Handler method for the 'GET_RAW_MESSAGE' requests. + + Implement this method in the sub class if you want + to handle the contract requests manually. + + :param ledger_api: the ledger apis. + :param contract_address: the contract address. + :param kwargs: the keyword arguments. + :return: the tx # noqa: DAR202 + """ + raise NotImplementedError + + @classmethod + def get_state( + cls, ledger_api: LedgerApi, contract_address: str, **kwargs: Any + ) -> JSONLike: + """ + Handler method for the 'GET_STATE' requests. + + Implement this method in the sub class if you want + to handle the contract requests manually. + + :param ledger_api: the ledger apis. + :param contract_address: the contract address. + :param kwargs: the keyword arguments. + :return: the tx # noqa: DAR202 + """ + raise NotImplementedError + + @classmethod + def get_approve_tx( # pylint: disable=too-many-arguments + cls, + ledger_api: LedgerApi, + contract_address: str, + spender: str, + amount: int, + sender: str, + raise_on_try: bool = False, + ) -> JSONLike: + """Get approve tx.""" + instance = cls.get_instance( + ledger_api=ledger_api, + contract_address=contract_address, + ) + tx = instance.functions.approve(spender, amount).build_transaction( + { + "from": sender, + "gas": 1, + "gasPrice": ledger_api.api.eth.gas_price, + "nonce": ledger_api.api.eth.get_transaction_count(sender), + } + ) + return ledger_api.update_with_gas_estimate( + transaction=tx, + raise_on_try=raise_on_try, + ) + + @classmethod + def get_events( # pragma: nocover + cls, + ledger_api: LedgerApi, + contract_address: str, + event: str, + receipt: JSONLike, + ) -> JSONLike: + """Process receipt for events.""" + contract_interface = cls.get_instance( + ledger_api=ledger_api, + contract_address=contract_address, + ) + Event = getattr(contract_interface.events, event, None) + if Event is None: + return {"events": []} + return {"events": Event().process_receipt(receipt)} diff --git a/packages/valory/contracts/erc20/contract.yaml b/packages/valory/contracts/erc20/contract.yaml new file mode 100644 index 0000000000..a96f8a1d18 --- /dev/null +++ b/packages/valory/contracts/erc20/contract.yaml @@ -0,0 +1,17 @@ +name: erc20 +author: valory +version: 0.1.0 +type: contract +description: The scaffold contract scaffolds a contract to be implemented by the developer. +license: Apache-2.0 +aea_version: '>=1.0.0, <2.0.0' +fingerprint: + __init__.py: bafybeieeus2bbbexmthy4pnsdtgen4flxzk3ao5ekjbocvmrkhhszffbgu + build/ERC20.json: bafybeiccjj4jwmpianz6vsxtubzg7bkssorapbcti4fx3e5d7g32pqmtee + contract.py: bafybeici3fo2eb4h6camnmcnkefkrmphm5jszwbh2fkm6zobj4q6k6mfhq +fingerprint_ignore_patterns: [] +class_name: ERC20TokenContract +contract_interface_paths: + ethereum: build/ERC20.json +dependencies: {} +contracts: [] diff --git a/packages/valory/contracts/gnosis_safe/contract.py b/packages/valory/contracts/gnosis_safe/contract.py index caa761c58e..417a3913d2 100644 --- a/packages/valory/contracts/gnosis_safe/contract.py +++ b/packages/valory/contracts/gnosis_safe/contract.py @@ -32,11 +32,11 @@ from eth_typing import ChecksumAddress, HexAddress, HexStr from hexbytes import HexBytes from packaging.version import Version -from py_eth_sig_utils.eip712 import encode_typed_data from requests import HTTPError -from web3.exceptions import SolidityError, TransactionNotFound +from web3.exceptions import ContractLogicError, TransactionNotFound from web3.types import BlockIdentifier, Nonce, TxData, TxParams, Wei +from packages.valory.contracts.gnosis_safe.encode import encode_typed_data from packages.valory.contracts.gnosis_safe_proxy_factory.contract import ( GnosisSafeProxyFactoryContract, ) @@ -179,7 +179,7 @@ def _get_deploy_transaction( # pylint: disable=too-many-locals,too-many-argumen raise ValueError("Client does not have any funds") ether_account_balance = round( - ledger_api.api.fromWei(account_balance, "ether"), 6 + ledger_api.api.from_wei(account_balance, "ether"), 6 ) _logger.info( "Network %s - Sender %s - Balance: %sΞ", @@ -212,7 +212,7 @@ def _get_deploy_transaction( # pylint: disable=too-many-locals,too-many-argumen payment_token, payment, payment_receiver, - ).buildTransaction({"gas": MIN_GAS, "gasPrice": MIN_GASPRICE})["data"] + ).build_transaction({"gas": MIN_GAS, "gasPrice": MIN_GASPRICE})["data"] ) nonce = ( @@ -346,7 +346,7 @@ def get_raw_safe_transaction_hash( # pylint: disable=too-many-arguments,too-man return dict(tx_hash=HexBytes(encode_typed_data(structured_data)).hex()) @classmethod - def _get_packed_signatures( + def get_packed_signatures( cls, owners: Tuple[str], signatures_by_owner: Dict[str, str] ) -> bytes: """Get the packed signatures.""" @@ -411,10 +411,10 @@ def get_raw_safe_transaction( # pylint: disable=too-many-arguments,too-many-loc :param fallback_gas: (external) gas to spend when base_gas and safe_tx_gas are zero and no gas estimation is possible. :return: the raw Safe transaction """ - sender_address = ledger_api.api.toChecksumAddress(sender_address) - to_address = ledger_api.api.toChecksumAddress(to_address) + sender_address = ledger_api.api.to_checksum_address(sender_address) + to_address = ledger_api.api.to_checksum_address(to_address) ledger_api = cast(EthereumApi, ledger_api) - signatures = cls._get_packed_signatures(owners, signatures_by_owner) + signatures = cls.get_packed_signatures(owners, signatures_by_owner) safe_contract = cls.get_instance(ledger_api, contract_address) w3_tx = safe_contract.functions.execTransaction( @@ -440,7 +440,7 @@ def get_raw_safe_transaction( # pylint: disable=too-many-arguments,too-many-loc "gas": configured_gas, } actual_nonce = ledger_api.api.eth.get_transaction_count( - ledger_api.api.toChecksumAddress(sender_address) + ledger_api.api.to_checksum_address(sender_address) ) if actual_nonce != nonce: nonce = actual_nonce @@ -458,7 +458,7 @@ def get_raw_safe_transaction( # pylint: disable=too-many-arguments,too-many-loc ): tx_parameters.update(ledger_api.try_get_gas_pricing(old_price=old_price)) # note, the next line makes an eth_estimateGas call if gas is not set! - transaction_dict = w3_tx.buildTransaction(tx_parameters) + transaction_dict = w3_tx.build_transaction(tx_parameters) if configured_gas != MIN_GAS: transaction_dict["gas"] = Wei(configured_gas) else: @@ -532,10 +532,10 @@ def verify_tx( # pylint: disable=too-many-arguments,too-many-locals :param safe_version: Safe version 1.0.0 renamed `baseGas` to `dataGas`. Safe version 1.3.0 added `chainId` to the `domainSeparator`. If not provided, it will be retrieved from network :return: the verified status """ - to_address = ledger_api.api.toChecksumAddress(to_address) + to_address = ledger_api.api.to_checksum_address(to_address) ledger_api = cast(EthereumApi, ledger_api) safe_contract = cls.get_instance(ledger_api, contract_address) - signatures = cls._get_packed_signatures(owners, signatures_by_owner) + signatures = cls.get_packed_signatures(owners, signatures_by_owner) if safe_version is None: safe_version = safe_contract.functions.VERSION().call( @@ -632,7 +632,7 @@ def revert_reason( # pylint: disable=unused-argument try: # replay the transaction locally: ledger_api.api.eth.call(replay_tx, tx["blockNumber"] - 1) - except SolidityError as e: + except ContractLogicError as e: # execution reverted exception return dict(revert_reason=repr(e)) except HTTPError as e: # pragma: nocover @@ -681,7 +681,7 @@ def get_ingoing_transfers( current_block = ledger_api.api.eth.get_block("latest")["number"] from_block = hex(max(0, current_block - 50)) # check in the last ~10 min - safe_filter = safe_contract.events.SafeReceived.createFilter( + safe_filter = safe_contract.events.SafeReceived.create_filter( fromBlock=from_block, toBlock=to_block ) all_entries = safe_filter.get_all_entries() @@ -755,7 +755,7 @@ def get_safe_txs( ledger_api = cast(EthereumApi, ledger_api) factory_contract = cls.get_instance(ledger_api, contract_address) - entries = factory_contract.events.ExecutionSuccess.createFilter( + entries = factory_contract.events.ExecutionSuccess.create_filter( fromBlock=from_block, toBlock=to_block, ).get_all_entries() @@ -793,7 +793,7 @@ def get_removed_owner_events( """ ledger_api = cast(EthereumApi, ledger_api) safe_contract = cls.get_instance(ledger_api, contract_address) - entries = safe_contract.events.RemovedOwner.createFilter( + entries = safe_contract.events.RemovedOwner.create_filter( fromBlock=from_block, toBlock=to_block, ).get_all_entries() @@ -810,7 +810,7 @@ def get_removed_owner_events( data=removed_owner_events, ) - checksummed_removed_owner = ledger_api.api.toChecksumAddress(removed_owner) + checksummed_removed_owner = ledger_api.api.to_checksum_address(removed_owner) removed_owner_events = list( dict( tx_hash=entry.transactionHash.hex(), @@ -819,7 +819,7 @@ def get_removed_owner_events( ) for entry in entries if ( - ledger_api.api.toChecksumAddress(entry["args"]["owner"]) + ledger_api.api.to_checksum_address(entry["args"]["owner"]) == checksummed_removed_owner ) ) @@ -848,8 +848,8 @@ def get_zero_transfer_events( """ ledger_api = cast(EthereumApi, ledger_api) safe_contract = cls.get_instance(ledger_api, contract_address) - sender_address = ledger_api.api.toChecksumAddress(sender_address) - entries = safe_contract.events.SafeReceived.createFilter( + sender_address = ledger_api.api.to_checksum_address(sender_address) + entries = safe_contract.events.SafeReceived.create_filter( fromBlock=from_block, toBlock=to_block, argument_filters=dict(sender=sender_address), @@ -858,7 +858,7 @@ def get_zero_transfer_events( dict( tx_hash=entry.transactionHash.hex(), block_number=entry.blockNumber, - sender=ledger_api.api.toChecksumAddress(entry["args"]["sender"]), + sender=ledger_api.api.to_checksum_address(entry["args"]["sender"]), ) for entry in entries if int(entry["args"]["value"]) == 0 @@ -892,15 +892,15 @@ def get_remove_owner_data( # Note that owners in the safe are stored as a linked list, we need to know the parent (prev_owner) of an owner # when removing. https://github.com/safe-global/safe-contracts/blob/v1.3.0/contracts/base/OwnerManager.sol#L15 owners = [ - ledger_api.api.toChecksumAddress(owner) + ledger_api.api.to_checksum_address(owner) for owner in safe_contract.functions.getOwners().call() ] - owner = ledger_api.api.toChecksumAddress(owner) + owner = ledger_api.api.to_checksum_address(owner) prev_owner = cls._get_prev_owner(owners, owner) data = safe_contract.encodeABI( fn_name="removeOwner", args=[ - ledger_api.api.toChecksumAddress(prev_owner), + ledger_api.api.to_checksum_address(prev_owner), owner, threshold, ], @@ -934,17 +934,17 @@ def get_swap_owner_data( # Note that owners in the safe are stored as a linked list, we need to know the parent (prev_owner) of an owner # when swapping. https://github.com/safe-global/safe-contracts/blob/v1.3.0/contracts/base/OwnerManager.sol#L15 owners = [ - ledger_api.api.toChecksumAddress(owner) + ledger_api.api.to_checksum_address(owner) for owner in safe_contract.functions.getOwners().call() ] - old_owner = ledger_api.api.toChecksumAddress(old_owner) + old_owner = ledger_api.api.to_checksum_address(old_owner) prev_owner = cls._get_prev_owner(owners, old_owner) data = safe_contract.encodeABI( fn_name="swapOwner", args=[ - ledger_api.api.toChecksumAddress(prev_owner), + ledger_api.api.to_checksum_address(prev_owner), old_owner, - ledger_api.api.toChecksumAddress(new_owner), + ledger_api.api.to_checksum_address(new_owner), ], ) return dict( @@ -977,7 +977,28 @@ def get_owners( ledger_api = cast(EthereumApi, ledger_api) safe_contract = cls.get_instance(ledger_api, contract_address) owners = [ - ledger_api.api.toChecksumAddress(owner) + ledger_api.api.to_checksum_address(owner) for owner in safe_contract.functions.getOwners().call() ] return dict(owners=owners) + + @classmethod + def get_approve_hash_tx( + cls, + ledger_api: EthereumApi, + contract_address: str, + tx_hash: str, + sender: str, + ) -> JSONLike: + """Get approve has tx.""" + ledger_api = cast(EthereumApi, ledger_api) + return ledger_api.build_transaction( + contract_instance=cls.get_instance(ledger_api, contract_address), + method_name="approveHash", + method_args={ + "hashToApprove": tx_hash, + }, + tx_args={ + "sender_address": sender, + }, + ) diff --git a/packages/valory/contracts/gnosis_safe/contract.yaml b/packages/valory/contracts/gnosis_safe/contract.yaml index e25ce263ad..93b412fe04 100644 --- a/packages/valory/contracts/gnosis_safe/contract.yaml +++ b/packages/valory/contracts/gnosis_safe/contract.yaml @@ -9,26 +9,32 @@ fingerprint: README.md: bafybeig26vrs7tcobu4cgk3fpqhvlzjwmb4nqsc7u66n4yhd2dh2rt7ff4 __init__.py: bafybeib4nfvueif2tkc7migc73qopyjvrbzedyehrexjx4y5vav3clmf34 build/GnosisSafe_V1_3_0.json: bafybeifxc4pnyus43qfrvxrqunlmkzvwfr5chyjesyobbk5m4smb2hkd4y - contract.py: bafybeihdb5oeg4xtnapwml5qz5rkckfetam4wnc2n3gdws23mstpq33ue4 + contract.py: bafybeiasa5rs5axojfmuztc6powf7twkpwjiacw2fef3xymmd5jd6hz354 + encode.py: bafybeiez2siif4cpntxjvzcxsgpv2xcdgco4xtnr26pjqzwrlu62tmn2na tests/__init__.py: bafybeihbclcqwfoxoljzwnbg3nf22srsyx5dgdbcyj27irwizktg4ygujy - tests/test_contract.py: bafybeidnlxmcedoean6xfhjwvj5yvgbaxevjgtlu6wnu2w6y5a37hiniri + tests/test_contract.py: bafybeiccezfy6uu24owucy3klzddbtinfs6agyarzbekmtnq7dgruimz3y fingerprint_ignore_patterns: [] contracts: -- valory/gnosis_safe_proxy_factory:0.1.0:bafybeierle6peb4a5cw3tncgondwhgesomzg7tedkb5cuos2zm462asbdi +- valory/gnosis_safe_proxy_factory:0.1.0:bafybeiehjccqvhrcarhahhyyrshaifoipfqwvpxjucpucslp22l2wc3sl4 class_name: GnosisSafeContract contract_interface_paths: ethereum: build/GnosisSafe_V1_3_0.json dependencies: ecdsa: version: '>=0.15' + eth-abi: + version: ==4.0.0 + eth-utils: + version: ==2.2.0 eth_typing: {} hexbytes: {} open-aea-ledger-ethereum: - version: ==1.32.0 + version: ==1.43.0.post2 open-aea-test-autonomy: - version: ==0.10.2 + version: ==0.13.9.post1 packaging: {} - py-eth-sig-utils: {} + pycryptodome: + version: ==3.18.0 requests: {} web3: - version: ==5.25.0 + version: <7,>=6.0.0 diff --git a/packages/valory/contracts/gnosis_safe/encode.py b/packages/valory/contracts/gnosis_safe/encode.py new file mode 100644 index 0000000000..e65cf5e0a7 --- /dev/null +++ b/packages/valory/contracts/gnosis_safe/encode.py @@ -0,0 +1,155 @@ +# -*- coding: utf-8 -*- +# ------------------------------------------------------------------------------ +# +# Copyright 2023 Valory AG +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# ------------------------------------------------------------------------------ + +"""ETH encoder.""" + +import typing as t + +from Crypto.Hash import keccak # nosec +from eth_abi.abi import default_codec # nosec +from eth_utils import decode_hex + + +def encode(typ: t.Any, arg: t.Any) -> bytes: + """Encode by type.""" + encoder = default_codec._registry.get_encoder( # pylint: disable=protected-access + typ + ) + return encoder(arg) + + +def to_string(value: t.Union[bytes, str, int]) -> bytes: + """Convert to byte string.""" + if isinstance(value, bytes): + return value + if isinstance(value, str): + return bytes(value, "utf-8") + if isinstance(value, int): + return bytes(str(value), "utf-8") + raise ValueError("Invalid data") + + +def sha3_256(x: bytes) -> bytes: + """Calculate SHA3-256 hash.""" + return keccak.new(digest_bits=256, data=x).digest() + + +def sha3(seed: t.Union[bytes, str, int]) -> bytes: + """Calculate SHA3-256 hash.""" + return sha3_256(to_string(seed)) + + +def scan_bin(v: str) -> bytes: + """Scan bytes.""" + if v[:2] in ("0x", b"0x"): + return decode_hex(v[2:]) + return decode_hex(v) + + +def create_struct_definition(name: str, schema: t.List[t.Dict[str, str]]) -> str: + """Create method struction defintion.""" + schema_types = [ + (schema_type["type"] + " " + schema_type["name"]) for schema_type in schema + ] + return name + "(" + ",".join(schema_types) + ")" + + +def find_dependencies( + name: str, types: t.Dict[str, t.Any], dependencies: t.Set +) -> None: + """Find dependencies.""" + if name in dependencies: + return + schema = types.get(name) + if not schema: + return + dependencies.add(name) + for schema_type in schema: + find_dependencies(schema_type["type"], types, dependencies) + + +def create_schema(name: str, types: t.Dict) -> str: + """Create schema.""" + array_start = name.find("[") + clean_name = name if array_start < 0 else name[:array_start] + dependencies: t.Set = set() + find_dependencies(clean_name, types, dependencies) + dependencies.discard(clean_name) + dependency_definitions = [ + create_struct_definition(dependency, types[dependency]) + for dependency in sorted(dependencies) + if types.get(dependency) + ] + return create_struct_definition(clean_name, types[clean_name]) + "".join( + dependency_definitions + ) + + +def create_schema_hash(name: str, types: t.Dict) -> bytes: + """Create schema hash.""" + return encode("bytes32", sha3(create_schema(name, types))) + + +def encode_value(data_type: str, value: t.Any, types: t.Dict) -> bytes: + """Encode value.""" + if data_type == "string": + return encode("bytes32", sha3(value)) + if data_type == "bytes": + return encode("bytes32", sha3(scan_bin(value))) + if types.get(data_type): + return encode("bytes32", sha3(encode_data(data_type, value, types))) + if data_type.endswith("]"): + arrayType = data_type[: data_type.index("[")] + return encode( + "bytes32", + sha3( + b"".join( + [encode_data(arrayType, arrayValue, types) for arrayValue in value] + ) + ), + ) + return encode(data_type, value) + + +def encode_data(name: str, data: t.Dict[str, t.Dict[str, str]], types: t.Dict) -> bytes: + """Encode data.""" + return create_schema_hash(name, types) + b"".join( + [ + encode_value(schema_type["type"], data[schema_type["name"]], types) + for schema_type in types[name] + ] + ) + + +def create_struct_hash( + name: str, data: t.Dict[str, t.Dict[str, str]], types: t.Dict +) -> bytes: + """Create struct hash.""" + return sha3(encode_data(name, data, types)) + + +def encode_typed_data(data: t.Dict[str, t.Any]) -> bytes: + """Encode typed data.""" + types = t.cast(t.Dict, data.get("types")) + primary_type = t.cast(str, data.get("primaryType")) + domain = t.cast(t.Dict[str, t.Dict[str, str]], data.get("domain")) + message = t.cast(t.Dict[str, t.Any], data.get("message")) + domain_hash = create_struct_hash("EIP712Domain", domain, types) + message_hash = create_struct_hash(primary_type, message, types) + return sha3(bytes.fromhex("19") + bytes.fromhex("01") + domain_hash + message_hash) diff --git a/packages/valory/contracts/gnosis_safe/tests/test_contract.py b/packages/valory/contracts/gnosis_safe/tests/test_contract.py index 097beb3d4f..1ce7c28fb8 100644 --- a/packages/valory/contracts/gnosis_safe/tests/test_contract.py +++ b/packages/valory/contracts/gnosis_safe/tests/test_contract.py @@ -46,7 +46,7 @@ from web3 import Web3 from web3.datastructures import AttributeDict from web3.eth import Eth -from web3.exceptions import SolidityError +from web3.exceptions import ContractLogicError from web3.types import TxData from packages.valory.contracts.gnosis_safe.contract import ( @@ -106,7 +106,9 @@ def deployment_kwargs(cls) -> Dict[str, Any]: @classmethod def owners(cls) -> List[str]: """Get the owners.""" - return [Web3.toChecksumAddress(t[0]) for t in cls.key_pairs()[: cls.NB_OWNERS]] + return [ + Web3.to_checksum_address(t[0]) for t in cls.key_pairs()[: cls.NB_OWNERS] + ] @classmethod def deployer(cls) -> Tuple[str, str]: @@ -159,7 +161,9 @@ def deployment_kwargs(cls) -> Dict[str, Any]: @classmethod def owners(cls) -> List[str]: """Get the owners.""" - return [Web3.toChecksumAddress(t[0]) for t in cls.key_pairs()[: cls.NB_OWNERS]] + return [ + Web3.to_checksum_address(t[0]) for t in cls.key_pairs()[: cls.NB_OWNERS] + ] @classmethod def deployer(cls) -> Tuple[str, str]: @@ -340,7 +344,7 @@ def test_revert_reason( } def _raise_solidity_error(*_: Any) -> None: - raise SolidityError("reason") + raise ContractLogicError("reason") with mock.patch.object( self.ledger_api.api.eth, "call", new=_raise_solidity_error @@ -349,7 +353,7 @@ def _raise_solidity_error(*_: Any) -> None: self.ledger_api, "contract_address", cast(TxData, tx) ) assert "revert_reason" in reason - assert reason["revert_reason"] == "SolidityError('reason')" + assert reason["revert_reason"] == "ContractLogicError('reason')" with mock.patch.object(self.ledger_api.api.eth, "call"), pytest.raises( ValueError, match=f"The given transaction has not been reverted!\ntx: {tx}" diff --git a/packages/valory/contracts/gnosis_safe_proxy_factory/contract.py b/packages/valory/contracts/gnosis_safe_proxy_factory/contract.py index 0f2d9bbde2..0294e5be02 100644 --- a/packages/valory/contracts/gnosis_safe_proxy_factory/contract.py +++ b/packages/valory/contracts/gnosis_safe_proxy_factory/contract.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- # ------------------------------------------------------------------------------ # -# Copyright 2021-2022 Valory AG +# Copyright 2021-2023 Valory AG # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -146,7 +146,7 @@ def build_tx_deploy_proxy_contract_with_nonce( # pylint: disable=too-many-argum if nonce is not None: tx_parameters["nonce"] = Nonce(nonce) - transaction_dict = create_proxy_fn.buildTransaction(tx_parameters) + transaction_dict = create_proxy_fn.build_transaction(tx_parameters) gas_estimate = ( ledger_api._try_get_gas_estimate( # pylint: disable=protected-access transaction_dict diff --git a/packages/valory/contracts/gnosis_safe_proxy_factory/contract.yaml b/packages/valory/contracts/gnosis_safe_proxy_factory/contract.yaml index 78d2e18733..90522464f0 100644 --- a/packages/valory/contracts/gnosis_safe_proxy_factory/contract.yaml +++ b/packages/valory/contracts/gnosis_safe_proxy_factory/contract.yaml @@ -9,7 +9,7 @@ fingerprint: README.md: bafybeibobgyzn3kozckup5uxbugbgkiqrc7d5okmj6gahctccqfifu7e4e __init__.py: bafybeif32mykzila23udgceziog2zr4tkreij6zn43ybbtzonojsfmy5ee build/ProxyFactory_V1_3_0.json: bafybeibmhgw6us3nzg5d4vb3krg3udxgnux66vuz26pjcigdjc7zn5jrxm - contract.py: bafybeih7756f2ba6m2w5w4zhxck2bowngudbhfj5ylppxyidzmsojpsk3q + contract.py: bafybeiefqqgav5dfw5p7nnwd3yq7ls4636dgsaolkau2nd5tslsvp66m6u tests/__init__.py: bafybeied5o76k2pgmpqlofnfo2mhoncecnigkm24t26qrnhhqzvtg3g3b4 tests/test_contract.py: bafybeidgcxvkl4xjg5dbjzl3o6ffoylkdewrpni6lxm3624qrebbwmqeay fingerprint_ignore_patterns: [] @@ -19,9 +19,8 @@ contract_interface_paths: ethereum: build/ProxyFactory_V1_3_0.json dependencies: open-aea-ledger-ethereum: - version: ==1.32.0 + version: ==1.43.0.post2 open-aea-test-autonomy: - version: ==0.10.2 - py-eth-sig-utils: {} + version: ==0.13.9.post1 web3: - version: ==5.25.0 + version: <7,>=6.0.0 diff --git a/packages/valory/contracts/multicall2/contract.py b/packages/valory/contracts/multicall2/contract.py index 4546075a09..f1b194fc63 100755 --- a/packages/valory/contracts/multicall2/contract.py +++ b/packages/valory/contracts/multicall2/contract.py @@ -152,5 +152,5 @@ def aggregate_and_decode( decoder(call_response) for decoder, call_response in zip(decoders, call_responses) ] - block_number = ledger_api.api.eth.blockNumber + block_number = ledger_api.api.eth.block_number return block_number, decoded_responses diff --git a/packages/valory/contracts/multicall2/contract.yaml b/packages/valory/contracts/multicall2/contract.yaml index 0868689dcc..fe1025d3af 100755 --- a/packages/valory/contracts/multicall2/contract.yaml +++ b/packages/valory/contracts/multicall2/contract.yaml @@ -8,7 +8,7 @@ aea_version: '>=1.0.0, <2.0.0' fingerprint: __init__.py: bafybeiblecacbcjfghnmqw3ttmgm3kiyhpdhmwfi77jowsab5y7gy2cqn4 build/multicall2.json: bafybeiccd7a7mwq4z62voom765tijsdc4qjnl6u23qg5upqepa5lo2262q - contract.py: bafybeig2azsvda7xcf7xsg46kwttgmn4gfeszxhyvl5qbfj4kbc5j2rddy + contract.py: bafybeigaeyg5ovhzlxxkd2hezppfyusji6e6a7ckxineuwxvahbn64ptpy tests/__init__.py: bafybeidpkdejmolv6wufw2ik36fdtymdscfrjvmg6ekjk7u4ikifmsnega tests/test_contract.py: bafybeih4q6mlsqpug375nudfy4vyhrl5vu7fwt7w4xe6y264kcwp53zu3m fingerprint_ignore_patterns: [] @@ -18,6 +18,6 @@ contract_interface_paths: contracts: [] dependencies: open-aea-ledger-ethereum: - version: ==1.32.0 + version: ==1.43.0.post2 web3: - version: ==5.25.0 + version: <7,>=6.0.0 diff --git a/packages/valory/contracts/multisend/contract.py b/packages/valory/contracts/multisend/contract.py index b62b19b738..0082a6e61b 100644 --- a/packages/valory/contracts/multisend/contract.py +++ b/packages/valory/contracts/multisend/contract.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- # ------------------------------------------------------------------------------ # -# Copyright 2021-2022 Valory AG +# Copyright 2021-2023 Valory AG # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -65,7 +65,7 @@ def decode_data(encoded_tx: bytes) -> Tuple[Dict, int]: """Decodes multisend transaction.""" encoded_tx = HexBytes(encoded_tx) operation = MultiSendOperation(encoded_tx[0]) - to = Web3.toChecksumAddress(encoded_tx[1 : 1 + 20]) + to = Web3.to_checksum_address(encoded_tx[1 : 1 + 20]) value = int.from_bytes(encoded_tx[21 : 21 + 32], byteorder="big") data_length = int.from_bytes(encoded_tx[21 + 32 : 21 + 32 * 2], byteorder="big") data = encoded_tx[21 + 32 * 2 : 21 + 32 * 2 + data_length] @@ -148,9 +148,30 @@ def get_tx_data( return { "data": multisend_contract.functions.multiSend( encoded_multisend_data - ).buildTransaction({"gas": MIN_GAS, "gasPrice": MIN_GASPRICE})["data"] + ).build_transaction({"gas": MIN_GAS, "gasPrice": MIN_GASPRICE})["data"] } + @classmethod + def get_multisend_tx( + cls, + ledger_api: LedgerApi, + contract_address: str, + txs: List[Dict], + ) -> Optional[JSONLike]: + """ + Get a multisend transaction data from list. + + :param ledger_api: ledger API object. + :param contract_address: the contract address. + :param txs: the multisend transaction list. + :return: an optional JSON-like object. + """ + multisend_contract = cls.get_instance(ledger_api, contract_address) + encoded_multisend_data = to_bytes(txs) + return multisend_contract.functions.multiSend( + encoded_multisend_data + ).build_transaction({"gas": MIN_GAS, "gasPrice": MIN_GASPRICE}) + @classmethod def get_tx_list( cls, ledger_api: LedgerApi, contract_address: str, multi_send_data: str diff --git a/packages/valory/contracts/multisend/contract.yaml b/packages/valory/contracts/multisend/contract.yaml index 83a26209b2..9128ba6ad9 100644 --- a/packages/valory/contracts/multisend/contract.yaml +++ b/packages/valory/contracts/multisend/contract.yaml @@ -9,7 +9,7 @@ fingerprint: README.md: bafybeidavn55z6uoz3hdjxs4ukvykl2tkvbntnl22uexfyk7unpnfqjflq __init__.py: bafybeigzxw44dlgdb4qxhm6zul426uyxnqtlhe3oajivdyo3ue7kb45pai build/MultiSend.json: bafybeicamzvsaaxtboijwfnv24ctrgv5v7gn5irnydnuf62y57o7fmx2jm - contract.py: bafybeieql2vyh5pfjnl3zzbzxwr3adnnccqyxt3drbdq6loe3o7eac2isu + contract.py: bafybeid5h5sro6nt7jmr52ntqdwo4ajhdyxy5estq625gzvo3dbkjuzxia tests/__init__.py: bafybeifd5zc6x3oxef7uy6mhjnt6oybna6ux7ycareqoqo52czkfxaeawm tests/test_contract.py: bafybeid72mml6mvtv6qqr7r6a2nfbgbwpkhyitx5mmdtzcejt5zo7wcmje fingerprint_ignore_patterns: [] @@ -20,4 +20,4 @@ contract_interface_paths: dependencies: hexbytes: {} web3: - version: ==5.25.0 + version: <7,>=6.0.0 diff --git a/packages/valory/contracts/registries_manager/contract.py b/packages/valory/contracts/registries_manager/contract.py index 4710abba4f..4c5512dc16 100644 --- a/packages/valory/contracts/registries_manager/contract.py +++ b/packages/valory/contracts/registries_manager/contract.py @@ -99,3 +99,33 @@ def get_create_transaction( # pylint: disable=too-many-arguments raise_on_try=raise_on_try, ) return tx_params + + @classmethod + def get_update_hash_transaction( # pylint: disable=too-many-arguments + cls, + ledger_api: LedgerApi, + contract_address: str, + component_type: UnitType, + unit_id: int, + metadata_hash: str, + sender: str, + raise_on_try: bool = False, + ) -> JSONLike: + """Create a component.""" + + tx_params = ledger_api.build_transaction( + contract_instance=cls.get_instance( + ledger_api=ledger_api, contract_address=contract_address + ), + method_name="updateHash", + method_args={ + "unitType": component_type.value, + "unitId": unit_id, + "unitHash": metadata_hash, + }, + tx_args={ + "sender_address": sender, + }, + raise_on_try=raise_on_try, + ) + return tx_params diff --git a/packages/valory/contracts/registries_manager/contract.yaml b/packages/valory/contracts/registries_manager/contract.yaml index 16ac07fce6..34ee05e97d 100644 --- a/packages/valory/contracts/registries_manager/contract.yaml +++ b/packages/valory/contracts/registries_manager/contract.yaml @@ -8,13 +8,12 @@ aea_version: '>=1.0.0, <2.0.0' fingerprint: __init__.py: bafybeihqlwkxffyqkqzzoqbm3t5caqxl75po6yk5cfjg5jp56dy47qqmv4 build/RegistriesManager.json: bafybeigu6whhxx6zd7kqhmpjpak4ufj4az2jk4k4rwi4tshr25qzcb3e6q - contract.py: bafybeigmoo6jiu7gjnr4clwzulauhoivefaeau2oi7nrmg5pa5ua7ck4da + contract.py: bafybeiazlsfshosryjsdt5umzfxcagxcxlaarugok5mypadb7nvjhmvray tests/__init__.py: bafybeib4z5zjwvlk5x5shenb2hzkgh7qb6w236g6ygcbvezvo5dfxao4va - tests/test_contract.py: bafybeifmfuw3k7shrhmmdntladipccmvm4qlslqh65csjzo3rric2sv5ju + tests/test_contract.py: bafybeidio2tvmghemwy3gmwcsjrjrln6rgpe6dtzdxbz6miblnk7yfogmy fingerprint_ignore_patterns: [] contracts: [] class_name: RegistriesManagerContract contract_interface_paths: ethereum: build/RegistriesManager.json - ethereum_hwi: build/RegistriesManager.json dependencies: {} diff --git a/packages/valory/contracts/registries_manager/tests/test_contract.py b/packages/valory/contracts/registries_manager/tests/test_contract.py index fc7f80ac8f..e15843779f 100644 --- a/packages/valory/contracts/registries_manager/tests/test_contract.py +++ b/packages/valory/contracts/registries_manager/tests/test_contract.py @@ -71,3 +71,32 @@ def test_get_create_transaction(self) -> None: for key in tx.keys() ] ) + + def test_get_update_hash_transaction(self) -> None: + """Test `get_update_hash_transaction` method.""" + + tx = self.contract.get_update_hash_transaction( + ledger_api=self.ledger_api, + contract_address=self.contract_address, + metadata_hash=METADATA_HASH, + component_type=RegistriesManagerContract.UnitType.COMPONENT, + unit_id=3, + sender=self.deployer_crypto.address, + ) + + assert all( + [ + key + in [ + "chainId", + "nonce", + "value", + "gas", + "maxFeePerGas", + "maxPriorityFeePerGas", + "to", + "data", + ] + for key in tx.keys() + ] + ) diff --git a/packages/valory/contracts/service_manager/build/ServiceManager.json b/packages/valory/contracts/service_manager/build/ServiceManager.json index 0dd54fc9e4..57f1ebaefc 100644 --- a/packages/valory/contracts/service_manager/build/ServiceManager.json +++ b/packages/valory/contracts/service_manager/build/ServiceManager.json @@ -695,8 +695,8 @@ "type": "function" } ], - "bytecode": "0x60a060405234801561001057600080fd5b5060405161114538038061114583398101604081905261002f91610052565b6001600160a01b0316608052600080546001600160a01b03191633179055610082565b60006020828403121561006457600080fd5b81516001600160a01b038116811461007b57600080fd5b9392505050565b6080516110776100ce6000396000818161024d015281816102ca015281816103af015281816104c9015281816105580152818161060d01528181610784015261086301526110776000f3fe6080604052600436106100d25760003560e01c80637a828b281161007f578063a6f9dae111610059578063a6f9dae11461021b578063cbcf252a1461023b578063d03ca40a1461026f578063fbdeb3d71461028257600080fd5b80637a828b28146101c65780638456cb59146101e65780638da5cb5b146101fb57600080fd5b80634d5a5827116100b05780634d5a5827146101625780635c975abb146101855780636503f7e1146101a657600080fd5b80630d0d57a8146100d757806327de9e32146101145780633f4ba83a1461014b575b600080fd5b3480156100e357600080fd5b506100f76100f236600461096b565b6102b0565b6040516001600160a01b0390911681526020015b60405180910390f35b34801561012057600080fd5b5061013461012f366004610a1c565b610386565b60408051921515835260208301919091520161010b565b34801561015757600080fd5b50610160610426565b005b610175610170366004610a1c565b6104a2565b604051901515815260200161010b565b34801561019157600080fd5b5060005461017590600160a01b900460ff1681565b3480156101b257600080fd5b506101756101c1366004610b85565b61053e565b3480156101d257600080fd5b506101346101e1366004610a1c565b6105e4565b3480156101f257600080fd5b5061016061063c565b34801561020757600080fd5b506000546100f7906001600160a01b031681565b34801561022757600080fd5b50610160610236366004610c0b565b6106b9565b34801561024757600080fd5b506100f77f000000000000000000000000000000000000000000000000000000000000000081565b61017561027d366004610c2f565b610780565b34801561028e57600080fd5b506102a261029d366004610cfc565b610820565b60405190815260200161010b565b60405163f908bc7760e01b81526000906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063f908bc7790610305903390889088908890600401610d8d565b6020604051808303816000875af1158015610324573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103489190610e06565b6040519091506001600160a01b038216907fec97633905b1dbe9773a7536e9a986dcf89803e1193934b7b6d76587c68beb4090600090a29392505050565b6040516352e82ce560e11b81523360048201526024810182905260009081906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063a5d059ca906044015b60408051808303816000875af11580156103f8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061041c9190610e33565b9094909350915050565b6000546001600160a01b0316331461046b5760005460405163521eb56d60e11b81523360048201526001600160a01b0390911660248201526044015b60405180910390fd5b6000805460ff60a01b1916815560405133917faeb196d352664784d1900b0e7414a8face7d29f4dae8c4b0cf68ed477423bbf491a2565b60405163388fdbed60e21b8152336004820152602481018290526000906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063e23f6fb490349060440160206040518083038185885af1158015610513573d6000803e3d6000fd5b50505050506040513d601f19601f820116820180604052508101906105389190610e5f565b92915050565b60405163197f329f60e31b81526000906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063cbf994f8906105979033908a908a908a908a908a90600401610f0a565b6020604051808303816000875af11580156105b6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105da9190610e5f565b9695505050505050565b60405163ccc9305d60e01b81523360048201526024810182905260009081906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063ccc9305d906044016103da565b6000546001600160a01b0316331461067c5760005460405163521eb56d60e11b81523360048201526001600160a01b039091166024820152604401610462565b6000805460ff60a01b1916600160a01b17815560405133917f5ee71a369c8672edded508e624ffc9257fa1ae6886ef32905c18e60196bca39991a2565b6000546001600160a01b031633146106f95760005460405163521eb56d60e11b81523360048201526001600160a01b039091166024820152604401610462565b6001600160a01b0381166107205760405163d92e233d60e01b815260040160405180910390fd5b600080547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b038316908117825560405190917f4ffd725fc4a22075e9ec71c59edf9c38cdeb588a91b24fc5b61388c5be41282b91a250565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663dff7672434338787876040518663ffffffff1660e01b81526004016107d59493929190610f60565b60206040518083038185885af11580156107f3573d6000803e3d6000fd5b50505050506040513d601f19601f820116820180604052508101906108189190610e5f565b949350505050565b60008054600160a01b900460ff161561084c576040516313d0ff5960e31b815260040160405180910390fd5b60405163fbdeb3d760e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063fbdeb3d7906108a09089908990899089908990600401610fd5565b6020604051808303816000875af11580156108bf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105da9190611028565b6001600160a01b03811681146108f857600080fd5b50565b634e487b7160e01b600052604160045260246000fd5b6040805190810167ffffffffffffffff81118282101715610934576109346108fb565b60405290565b604051601f8201601f1916810167ffffffffffffffff81118282101715610963576109636108fb565b604052919050565b60008060006060848603121561098057600080fd5b83359250602080850135610993816108e3565b9250604085013567ffffffffffffffff808211156109b057600080fd5b818701915087601f8301126109c457600080fd5b8135818111156109d6576109d66108fb565b6109e8601f8201601f1916850161093a565b915080825288848285010111156109fe57600080fd5b80848401858401376000848284010152508093505050509250925092565b600060208284031215610a2e57600080fd5b5035919050565b600067ffffffffffffffff821115610a4f57610a4f6108fb565b5060051b60200190565b803563ffffffff81168114610a6d57600080fd5b919050565b600082601f830112610a8357600080fd5b81356020610a98610a9383610a35565b61093a565b82815260059290921b84018101918181019086841115610ab757600080fd5b8286015b84811015610ad957610acc81610a59565b8352918301918301610abb565b509695505050505050565b600082601f830112610af557600080fd5b81356020610b05610a9383610a35565b82815260069290921b84018101918181019086841115610b2457600080fd5b8286015b84811015610ad95760408189031215610b415760008081fd5b610b49610911565b610b5282610a59565b8152848201356bffffffffffffffffffffffff81168114610b735760008081fd5b81860152835291830191604001610b28565b600080600080600060a08688031215610b9d57600080fd5b85359450602086013567ffffffffffffffff80821115610bbc57600080fd5b610bc889838a01610a72565b95506040880135915080821115610bde57600080fd5b50610beb88828901610ae4565b935050610bfa60608701610a59565b949793965091946080013592915050565b600060208284031215610c1d57600080fd5b8135610c28816108e3565b9392505050565b600080600060608486031215610c4457600080fd5b8335925060208085013567ffffffffffffffff80821115610c6457600080fd5b818701915087601f830112610c7857600080fd5b8135610c86610a9382610a35565b81815260059190911b8301840190848101908a831115610ca557600080fd5b938501935b82851015610ccc578435610cbd816108e3565b82529385019390850190610caa565b965050506040870135925080831115610ce457600080fd5b5050610cf286828701610a72565b9150509250925092565b600080600080600060a08688031215610d1457600080fd5b8535610d1f816108e3565b945060208601359350604086013567ffffffffffffffff80821115610d4357600080fd5b610d4f89838a01610a72565b94506060880135915080821115610d6557600080fd5b50610d7288828901610ae4565b925050610d8160808701610a59565b90509295509295909350565b60006001600160a01b038087168352602086818501528186166040850152608060608501528451915081608085015260005b82811015610ddb5785810182015185820160a001528101610dbf565b82811115610ded57600060a084870101525b5050601f01601f19169190910160a00195945050505050565b600060208284031215610e1857600080fd5b8151610c28816108e3565b80518015158114610a6d57600080fd5b60008060408385031215610e4657600080fd5b610e4f83610e23565b9150602083015190509250929050565b600060208284031215610e7157600080fd5b610c2882610e23565b600081518084526020808501945080840160005b83811015610eb057815163ffffffff1687529582019590820190600101610e8e565b509495945050505050565b600081518084526020808501945080840160005b83811015610eb0578151805163ffffffff1688528301516bffffffffffffffffffffffff168388015260409096019590820190600101610ecf565b6001600160a01b038716815285602082015260c060408201526000610f3260c0830187610e7a565b8281036060840152610f448187610ebb565b63ffffffff959095166080840152505060a00152949350505050565b6000608082016001600160a01b038088168452602087818601526080604086015282875180855260a087019150828901945060005b81811015610fb3578551851683529483019491830191600101610f95565b50508581036060870152610fc78188610e7a565b9a9950505050505050505050565b6001600160a01b038616815284602082015260a060408201526000610ffd60a0830186610e7a565b828103606084015261100f8186610ebb565b91505063ffffffff831660808301529695505050505050565b60006020828403121561103a57600080fd5b505191905056fea264697066735822122048139536f1550689697c21c8cfa1bae7d415f5adaddb174b8ed6cb01a5e0c2cb64736f6c634300080f0033", - "deployedBytecode": "0x6080604052600436106100d25760003560e01c80637a828b281161007f578063a6f9dae111610059578063a6f9dae11461021b578063cbcf252a1461023b578063d03ca40a1461026f578063fbdeb3d71461028257600080fd5b80637a828b28146101c65780638456cb59146101e65780638da5cb5b146101fb57600080fd5b80634d5a5827116100b05780634d5a5827146101625780635c975abb146101855780636503f7e1146101a657600080fd5b80630d0d57a8146100d757806327de9e32146101145780633f4ba83a1461014b575b600080fd5b3480156100e357600080fd5b506100f76100f236600461096b565b6102b0565b6040516001600160a01b0390911681526020015b60405180910390f35b34801561012057600080fd5b5061013461012f366004610a1c565b610386565b60408051921515835260208301919091520161010b565b34801561015757600080fd5b50610160610426565b005b610175610170366004610a1c565b6104a2565b604051901515815260200161010b565b34801561019157600080fd5b5060005461017590600160a01b900460ff1681565b3480156101b257600080fd5b506101756101c1366004610b85565b61053e565b3480156101d257600080fd5b506101346101e1366004610a1c565b6105e4565b3480156101f257600080fd5b5061016061063c565b34801561020757600080fd5b506000546100f7906001600160a01b031681565b34801561022757600080fd5b50610160610236366004610c0b565b6106b9565b34801561024757600080fd5b506100f77f000000000000000000000000000000000000000000000000000000000000000081565b61017561027d366004610c2f565b610780565b34801561028e57600080fd5b506102a261029d366004610cfc565b610820565b60405190815260200161010b565b60405163f908bc7760e01b81526000906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063f908bc7790610305903390889088908890600401610d8d565b6020604051808303816000875af1158015610324573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103489190610e06565b6040519091506001600160a01b038216907fec97633905b1dbe9773a7536e9a986dcf89803e1193934b7b6d76587c68beb4090600090a29392505050565b6040516352e82ce560e11b81523360048201526024810182905260009081906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063a5d059ca906044015b60408051808303816000875af11580156103f8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061041c9190610e33565b9094909350915050565b6000546001600160a01b0316331461046b5760005460405163521eb56d60e11b81523360048201526001600160a01b0390911660248201526044015b60405180910390fd5b6000805460ff60a01b1916815560405133917faeb196d352664784d1900b0e7414a8face7d29f4dae8c4b0cf68ed477423bbf491a2565b60405163388fdbed60e21b8152336004820152602481018290526000906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063e23f6fb490349060440160206040518083038185885af1158015610513573d6000803e3d6000fd5b50505050506040513d601f19601f820116820180604052508101906105389190610e5f565b92915050565b60405163197f329f60e31b81526000906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063cbf994f8906105979033908a908a908a908a908a90600401610f0a565b6020604051808303816000875af11580156105b6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105da9190610e5f565b9695505050505050565b60405163ccc9305d60e01b81523360048201526024810182905260009081906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063ccc9305d906044016103da565b6000546001600160a01b0316331461067c5760005460405163521eb56d60e11b81523360048201526001600160a01b039091166024820152604401610462565b6000805460ff60a01b1916600160a01b17815560405133917f5ee71a369c8672edded508e624ffc9257fa1ae6886ef32905c18e60196bca39991a2565b6000546001600160a01b031633146106f95760005460405163521eb56d60e11b81523360048201526001600160a01b039091166024820152604401610462565b6001600160a01b0381166107205760405163d92e233d60e01b815260040160405180910390fd5b600080547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b038316908117825560405190917f4ffd725fc4a22075e9ec71c59edf9c38cdeb588a91b24fc5b61388c5be41282b91a250565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663dff7672434338787876040518663ffffffff1660e01b81526004016107d59493929190610f60565b60206040518083038185885af11580156107f3573d6000803e3d6000fd5b50505050506040513d601f19601f820116820180604052508101906108189190610e5f565b949350505050565b60008054600160a01b900460ff161561084c576040516313d0ff5960e31b815260040160405180910390fd5b60405163fbdeb3d760e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063fbdeb3d7906108a09089908990899089908990600401610fd5565b6020604051808303816000875af11580156108bf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105da9190611028565b6001600160a01b03811681146108f857600080fd5b50565b634e487b7160e01b600052604160045260246000fd5b6040805190810167ffffffffffffffff81118282101715610934576109346108fb565b60405290565b604051601f8201601f1916810167ffffffffffffffff81118282101715610963576109636108fb565b604052919050565b60008060006060848603121561098057600080fd5b83359250602080850135610993816108e3565b9250604085013567ffffffffffffffff808211156109b057600080fd5b818701915087601f8301126109c457600080fd5b8135818111156109d6576109d66108fb565b6109e8601f8201601f1916850161093a565b915080825288848285010111156109fe57600080fd5b80848401858401376000848284010152508093505050509250925092565b600060208284031215610a2e57600080fd5b5035919050565b600067ffffffffffffffff821115610a4f57610a4f6108fb565b5060051b60200190565b803563ffffffff81168114610a6d57600080fd5b919050565b600082601f830112610a8357600080fd5b81356020610a98610a9383610a35565b61093a565b82815260059290921b84018101918181019086841115610ab757600080fd5b8286015b84811015610ad957610acc81610a59565b8352918301918301610abb565b509695505050505050565b600082601f830112610af557600080fd5b81356020610b05610a9383610a35565b82815260069290921b84018101918181019086841115610b2457600080fd5b8286015b84811015610ad95760408189031215610b415760008081fd5b610b49610911565b610b5282610a59565b8152848201356bffffffffffffffffffffffff81168114610b735760008081fd5b81860152835291830191604001610b28565b600080600080600060a08688031215610b9d57600080fd5b85359450602086013567ffffffffffffffff80821115610bbc57600080fd5b610bc889838a01610a72565b95506040880135915080821115610bde57600080fd5b50610beb88828901610ae4565b935050610bfa60608701610a59565b949793965091946080013592915050565b600060208284031215610c1d57600080fd5b8135610c28816108e3565b9392505050565b600080600060608486031215610c4457600080fd5b8335925060208085013567ffffffffffffffff80821115610c6457600080fd5b818701915087601f830112610c7857600080fd5b8135610c86610a9382610a35565b81815260059190911b8301840190848101908a831115610ca557600080fd5b938501935b82851015610ccc578435610cbd816108e3565b82529385019390850190610caa565b965050506040870135925080831115610ce457600080fd5b5050610cf286828701610a72565b9150509250925092565b600080600080600060a08688031215610d1457600080fd5b8535610d1f816108e3565b945060208601359350604086013567ffffffffffffffff80821115610d4357600080fd5b610d4f89838a01610a72565b94506060880135915080821115610d6557600080fd5b50610d7288828901610ae4565b925050610d8160808701610a59565b90509295509295909350565b60006001600160a01b038087168352602086818501528186166040850152608060608501528451915081608085015260005b82811015610ddb5785810182015185820160a001528101610dbf565b82811115610ded57600060a084870101525b5050601f01601f19169190910160a00195945050505050565b600060208284031215610e1857600080fd5b8151610c28816108e3565b80518015158114610a6d57600080fd5b60008060408385031215610e4657600080fd5b610e4f83610e23565b9150602083015190509250929050565b600060208284031215610e7157600080fd5b610c2882610e23565b600081518084526020808501945080840160005b83811015610eb057815163ffffffff1687529582019590820190600101610e8e565b509495945050505050565b600081518084526020808501945080840160005b83811015610eb0578151805163ffffffff1688528301516bffffffffffffffffffffffff168388015260409096019590820190600101610ecf565b6001600160a01b038716815285602082015260c060408201526000610f3260c0830187610e7a565b8281036060840152610f448187610ebb565b63ffffffff959095166080840152505060a00152949350505050565b6000608082016001600160a01b038088168452602087818601526080604086015282875180855260a087019150828901945060005b81811015610fb3578551851683529483019491830191600101610f95565b50508581036060870152610fc78188610e7a565b9a9950505050505050505050565b6001600160a01b038616815284602082015260a060408201526000610ffd60a0830186610e7a565b828103606084015261100f8186610ebb565b91505063ffffffff831660808301529695505050505050565b60006020828403121561103a57600080fd5b505191905056fea264697066735822122048139536f1550689697c21c8cfa1bae7d415f5adaddb174b8ed6cb01a5e0c2cb64736f6c634300080f0033", + "bytecode": "0x60a060405234801561001057600080fd5b5060405161113e38038061113e83398101604081905261002f91610052565b6001600160a01b0316608052600080546001600160a01b03191633179055610082565b60006020828403121561006457600080fd5b81516001600160a01b038116811461007b57600080fd5b9392505050565b6080516110706100ce6000396000818161024d015281816102ca015281816103af015281816104c9015281816105580152818161060d01528181610784015261086301526110706000f3fe6080604052600436106100d25760003560e01c80637a828b281161007f578063a6f9dae111610059578063a6f9dae11461021b578063cbcf252a1461023b578063d03ca40a1461026f578063fbdeb3d71461028257600080fd5b80637a828b28146101c65780638456cb59146101e65780638da5cb5b146101fb57600080fd5b80634d5a5827116100b05780634d5a5827146101625780635c975abb146101855780636503f7e1146101a657600080fd5b80630d0d57a8146100d757806327de9e32146101145780633f4ba83a1461014b575b600080fd5b3480156100e357600080fd5b506100f76100f236600461096b565b6102b0565b6040516001600160a01b0390911681526020015b60405180910390f35b34801561012057600080fd5b5061013461012f366004610a1c565b610386565b60408051921515835260208301919091520161010b565b34801561015757600080fd5b50610160610426565b005b610175610170366004610a1c565b6104a2565b604051901515815260200161010b565b34801561019157600080fd5b5060005461017590600160a01b900460ff1681565b3480156101b257600080fd5b506101756101c1366004610b85565b61053e565b3480156101d257600080fd5b506101346101e1366004610a1c565b6105e4565b3480156101f257600080fd5b5061016061063c565b34801561020757600080fd5b506000546100f7906001600160a01b031681565b34801561022757600080fd5b50610160610236366004610c0b565b6106b9565b34801561024757600080fd5b506100f77f000000000000000000000000000000000000000000000000000000000000000081565b61017561027d366004610c2f565b610780565b34801561028e57600080fd5b506102a261029d366004610cfc565b610820565b60405190815260200161010b565b60405163f908bc7760e01b81526000906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063f908bc7790610305903390889088908890600401610d8d565b6020604051808303816000875af1158015610324573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103489190610dff565b6040519091506001600160a01b038216907fec97633905b1dbe9773a7536e9a986dcf89803e1193934b7b6d76587c68beb4090600090a29392505050565b6040516352e82ce560e11b81523360048201526024810182905260009081906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063a5d059ca906044015b60408051808303816000875af11580156103f8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061041c9190610e2c565b9094909350915050565b6000546001600160a01b0316331461046b5760005460405163521eb56d60e11b81523360048201526001600160a01b0390911660248201526044015b60405180910390fd5b6000805460ff60a01b1916815560405133917faeb196d352664784d1900b0e7414a8face7d29f4dae8c4b0cf68ed477423bbf491a2565b60405163388fdbed60e21b8152336004820152602481018290526000906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063e23f6fb490349060440160206040518083038185885af1158015610513573d6000803e3d6000fd5b50505050506040513d601f19601f820116820180604052508101906105389190610e58565b92915050565b60405163197f329f60e31b81526000906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063cbf994f8906105979033908a908a908a908a908a90600401610f03565b6020604051808303816000875af11580156105b6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105da9190610e58565b9695505050505050565b60405163ccc9305d60e01b81523360048201526024810182905260009081906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063ccc9305d906044016103da565b6000546001600160a01b0316331461067c5760005460405163521eb56d60e11b81523360048201526001600160a01b039091166024820152604401610462565b6000805460ff60a01b1916600160a01b17815560405133917f5ee71a369c8672edded508e624ffc9257fa1ae6886ef32905c18e60196bca39991a2565b6000546001600160a01b031633146106f95760005460405163521eb56d60e11b81523360048201526001600160a01b039091166024820152604401610462565b6001600160a01b0381166107205760405163d92e233d60e01b815260040160405180910390fd5b600080547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b038316908117825560405190917f4ffd725fc4a22075e9ec71c59edf9c38cdeb588a91b24fc5b61388c5be41282b91a250565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663dff7672434338787876040518663ffffffff1660e01b81526004016107d59493929190610f59565b60206040518083038185885af11580156107f3573d6000803e3d6000fd5b50505050506040513d601f19601f820116820180604052508101906108189190610e58565b949350505050565b60008054600160a01b900460ff161561084c576040516313d0ff5960e31b815260040160405180910390fd5b60405163fbdeb3d760e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063fbdeb3d7906108a09089908990899089908990600401610fce565b6020604051808303816000875af11580156108bf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105da9190611021565b6001600160a01b03811681146108f857600080fd5b50565b634e487b7160e01b600052604160045260246000fd5b6040805190810167ffffffffffffffff81118282101715610934576109346108fb565b60405290565b604051601f8201601f1916810167ffffffffffffffff81118282101715610963576109636108fb565b604052919050565b60008060006060848603121561098057600080fd5b83359250602080850135610993816108e3565b9250604085013567ffffffffffffffff808211156109b057600080fd5b818701915087601f8301126109c457600080fd5b8135818111156109d6576109d66108fb565b6109e8601f8201601f1916850161093a565b915080825288848285010111156109fe57600080fd5b80848401858401376000848284010152508093505050509250925092565b600060208284031215610a2e57600080fd5b5035919050565b600067ffffffffffffffff821115610a4f57610a4f6108fb565b5060051b60200190565b803563ffffffff81168114610a6d57600080fd5b919050565b600082601f830112610a8357600080fd5b81356020610a98610a9383610a35565b61093a565b82815260059290921b84018101918181019086841115610ab757600080fd5b8286015b84811015610ad957610acc81610a59565b8352918301918301610abb565b509695505050505050565b600082601f830112610af557600080fd5b81356020610b05610a9383610a35565b82815260069290921b84018101918181019086841115610b2457600080fd5b8286015b84811015610ad95760408189031215610b415760008081fd5b610b49610911565b610b5282610a59565b8152848201356bffffffffffffffffffffffff81168114610b735760008081fd5b81860152835291830191604001610b28565b600080600080600060a08688031215610b9d57600080fd5b85359450602086013567ffffffffffffffff80821115610bbc57600080fd5b610bc889838a01610a72565b95506040880135915080821115610bde57600080fd5b50610beb88828901610ae4565b935050610bfa60608701610a59565b949793965091946080013592915050565b600060208284031215610c1d57600080fd5b8135610c28816108e3565b9392505050565b600080600060608486031215610c4457600080fd5b8335925060208085013567ffffffffffffffff80821115610c6457600080fd5b818701915087601f830112610c7857600080fd5b8135610c86610a9382610a35565b81815260059190911b8301840190848101908a831115610ca557600080fd5b938501935b82851015610ccc578435610cbd816108e3565b82529385019390850190610caa565b965050506040870135925080831115610ce457600080fd5b5050610cf286828701610a72565b9150509250925092565b600080600080600060a08688031215610d1457600080fd5b8535610d1f816108e3565b945060208601359350604086013567ffffffffffffffff80821115610d4357600080fd5b610d4f89838a01610a72565b94506060880135915080821115610d6557600080fd5b50610d7288828901610ae4565b925050610d8160808701610a59565b90509295509295909350565b60006001600160a01b038087168352602086818501528186166040850152608060608501528451915081608085015260005b82811015610ddb5785810182015185820160a001528101610dbf565b5050600060a0828501015260a0601f19601f83011684010191505095945050505050565b600060208284031215610e1157600080fd5b8151610c28816108e3565b80518015158114610a6d57600080fd5b60008060408385031215610e3f57600080fd5b610e4883610e1c565b9150602083015190509250929050565b600060208284031215610e6a57600080fd5b610c2882610e1c565b600081518084526020808501945080840160005b83811015610ea957815163ffffffff1687529582019590820190600101610e87565b509495945050505050565b600081518084526020808501945080840160005b83811015610ea9578151805163ffffffff1688528301516bffffffffffffffffffffffff168388015260409096019590820190600101610ec8565b6001600160a01b038716815285602082015260c060408201526000610f2b60c0830187610e73565b8281036060840152610f3d8187610eb4565b63ffffffff959095166080840152505060a00152949350505050565b6000608082016001600160a01b038088168452602087818601526080604086015282875180855260a087019150828901945060005b81811015610fac578551851683529483019491830191600101610f8e565b50508581036060870152610fc08188610e73565b9a9950505050505050505050565b6001600160a01b038616815284602082015260a060408201526000610ff660a0830186610e73565b82810360608401526110088186610eb4565b91505063ffffffff831660808301529695505050505050565b60006020828403121561103357600080fd5b505191905056fea26469706673582212200d441fd292fb8401bc7bd86e3c620d2da28a6dd4b26317a9308b941130ce728364736f6c63430008130033", + "deployedBytecode": "0x6080604052600436106100d25760003560e01c80637a828b281161007f578063a6f9dae111610059578063a6f9dae11461021b578063cbcf252a1461023b578063d03ca40a1461026f578063fbdeb3d71461028257600080fd5b80637a828b28146101c65780638456cb59146101e65780638da5cb5b146101fb57600080fd5b80634d5a5827116100b05780634d5a5827146101625780635c975abb146101855780636503f7e1146101a657600080fd5b80630d0d57a8146100d757806327de9e32146101145780633f4ba83a1461014b575b600080fd5b3480156100e357600080fd5b506100f76100f236600461096b565b6102b0565b6040516001600160a01b0390911681526020015b60405180910390f35b34801561012057600080fd5b5061013461012f366004610a1c565b610386565b60408051921515835260208301919091520161010b565b34801561015757600080fd5b50610160610426565b005b610175610170366004610a1c565b6104a2565b604051901515815260200161010b565b34801561019157600080fd5b5060005461017590600160a01b900460ff1681565b3480156101b257600080fd5b506101756101c1366004610b85565b61053e565b3480156101d257600080fd5b506101346101e1366004610a1c565b6105e4565b3480156101f257600080fd5b5061016061063c565b34801561020757600080fd5b506000546100f7906001600160a01b031681565b34801561022757600080fd5b50610160610236366004610c0b565b6106b9565b34801561024757600080fd5b506100f77f000000000000000000000000000000000000000000000000000000000000000081565b61017561027d366004610c2f565b610780565b34801561028e57600080fd5b506102a261029d366004610cfc565b610820565b60405190815260200161010b565b60405163f908bc7760e01b81526000906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063f908bc7790610305903390889088908890600401610d8d565b6020604051808303816000875af1158015610324573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103489190610dff565b6040519091506001600160a01b038216907fec97633905b1dbe9773a7536e9a986dcf89803e1193934b7b6d76587c68beb4090600090a29392505050565b6040516352e82ce560e11b81523360048201526024810182905260009081906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063a5d059ca906044015b60408051808303816000875af11580156103f8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061041c9190610e2c565b9094909350915050565b6000546001600160a01b0316331461046b5760005460405163521eb56d60e11b81523360048201526001600160a01b0390911660248201526044015b60405180910390fd5b6000805460ff60a01b1916815560405133917faeb196d352664784d1900b0e7414a8face7d29f4dae8c4b0cf68ed477423bbf491a2565b60405163388fdbed60e21b8152336004820152602481018290526000906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063e23f6fb490349060440160206040518083038185885af1158015610513573d6000803e3d6000fd5b50505050506040513d601f19601f820116820180604052508101906105389190610e58565b92915050565b60405163197f329f60e31b81526000906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063cbf994f8906105979033908a908a908a908a908a90600401610f03565b6020604051808303816000875af11580156105b6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105da9190610e58565b9695505050505050565b60405163ccc9305d60e01b81523360048201526024810182905260009081906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063ccc9305d906044016103da565b6000546001600160a01b0316331461067c5760005460405163521eb56d60e11b81523360048201526001600160a01b039091166024820152604401610462565b6000805460ff60a01b1916600160a01b17815560405133917f5ee71a369c8672edded508e624ffc9257fa1ae6886ef32905c18e60196bca39991a2565b6000546001600160a01b031633146106f95760005460405163521eb56d60e11b81523360048201526001600160a01b039091166024820152604401610462565b6001600160a01b0381166107205760405163d92e233d60e01b815260040160405180910390fd5b600080547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b038316908117825560405190917f4ffd725fc4a22075e9ec71c59edf9c38cdeb588a91b24fc5b61388c5be41282b91a250565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663dff7672434338787876040518663ffffffff1660e01b81526004016107d59493929190610f59565b60206040518083038185885af11580156107f3573d6000803e3d6000fd5b50505050506040513d601f19601f820116820180604052508101906108189190610e58565b949350505050565b60008054600160a01b900460ff161561084c576040516313d0ff5960e31b815260040160405180910390fd5b60405163fbdeb3d760e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063fbdeb3d7906108a09089908990899089908990600401610fce565b6020604051808303816000875af11580156108bf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105da9190611021565b6001600160a01b03811681146108f857600080fd5b50565b634e487b7160e01b600052604160045260246000fd5b6040805190810167ffffffffffffffff81118282101715610934576109346108fb565b60405290565b604051601f8201601f1916810167ffffffffffffffff81118282101715610963576109636108fb565b604052919050565b60008060006060848603121561098057600080fd5b83359250602080850135610993816108e3565b9250604085013567ffffffffffffffff808211156109b057600080fd5b818701915087601f8301126109c457600080fd5b8135818111156109d6576109d66108fb565b6109e8601f8201601f1916850161093a565b915080825288848285010111156109fe57600080fd5b80848401858401376000848284010152508093505050509250925092565b600060208284031215610a2e57600080fd5b5035919050565b600067ffffffffffffffff821115610a4f57610a4f6108fb565b5060051b60200190565b803563ffffffff81168114610a6d57600080fd5b919050565b600082601f830112610a8357600080fd5b81356020610a98610a9383610a35565b61093a565b82815260059290921b84018101918181019086841115610ab757600080fd5b8286015b84811015610ad957610acc81610a59565b8352918301918301610abb565b509695505050505050565b600082601f830112610af557600080fd5b81356020610b05610a9383610a35565b82815260069290921b84018101918181019086841115610b2457600080fd5b8286015b84811015610ad95760408189031215610b415760008081fd5b610b49610911565b610b5282610a59565b8152848201356bffffffffffffffffffffffff81168114610b735760008081fd5b81860152835291830191604001610b28565b600080600080600060a08688031215610b9d57600080fd5b85359450602086013567ffffffffffffffff80821115610bbc57600080fd5b610bc889838a01610a72565b95506040880135915080821115610bde57600080fd5b50610beb88828901610ae4565b935050610bfa60608701610a59565b949793965091946080013592915050565b600060208284031215610c1d57600080fd5b8135610c28816108e3565b9392505050565b600080600060608486031215610c4457600080fd5b8335925060208085013567ffffffffffffffff80821115610c6457600080fd5b818701915087601f830112610c7857600080fd5b8135610c86610a9382610a35565b81815260059190911b8301840190848101908a831115610ca557600080fd5b938501935b82851015610ccc578435610cbd816108e3565b82529385019390850190610caa565b965050506040870135925080831115610ce457600080fd5b5050610cf286828701610a72565b9150509250925092565b600080600080600060a08688031215610d1457600080fd5b8535610d1f816108e3565b945060208601359350604086013567ffffffffffffffff80821115610d4357600080fd5b610d4f89838a01610a72565b94506060880135915080821115610d6557600080fd5b50610d7288828901610ae4565b925050610d8160808701610a59565b90509295509295909350565b60006001600160a01b038087168352602086818501528186166040850152608060608501528451915081608085015260005b82811015610ddb5785810182015185820160a001528101610dbf565b5050600060a0828501015260a0601f19601f83011684010191505095945050505050565b600060208284031215610e1157600080fd5b8151610c28816108e3565b80518015158114610a6d57600080fd5b60008060408385031215610e3f57600080fd5b610e4883610e1c565b9150602083015190509250929050565b600060208284031215610e6a57600080fd5b610c2882610e1c565b600081518084526020808501945080840160005b83811015610ea957815163ffffffff1687529582019590820190600101610e87565b509495945050505050565b600081518084526020808501945080840160005b83811015610ea9578151805163ffffffff1688528301516bffffffffffffffffffffffff168388015260409096019590820190600101610ec8565b6001600160a01b038716815285602082015260c060408201526000610f2b60c0830187610e73565b8281036060840152610f3d8187610eb4565b63ffffffff959095166080840152505060a00152949350505050565b6000608082016001600160a01b038088168452602087818601526080604086015282875180855260a087019150828901945060005b81811015610fac578551851683529483019491830191600101610f8e565b50508581036060870152610fc08188610e73565b9a9950505050505050505050565b6001600160a01b038616815284602082015260a060408201526000610ff660a0830186610e73565b82810360608401526110088186610eb4565b91505063ffffffff831660808301529695505050505050565b60006020828403121561103357600080fd5b505191905056fea26469706673582212200d441fd292fb8401bc7bd86e3c620d2da28a6dd4b26317a9308b941130ce728364736f6c63430008130033", "linkReferences": {}, "deployedLinkReferences": {} } \ No newline at end of file diff --git a/packages/valory/contracts/service_manager/build/ServiceManagerToken.json b/packages/valory/contracts/service_manager/build/ServiceManagerToken.json new file mode 100644 index 0000000000..114f0e2e34 --- /dev/null +++ b/packages/valory/contracts/service_manager/build/ServiceManagerToken.json @@ -0,0 +1,1331 @@ +{ + "_format": "hh-sol-artifact-1", + "contractName": "ServiceManagerToken", + "sourceName": "contracts/ServiceManagerToken.sol", + "abi": [ + { + "inputs": [ + { + "internalType": "address", + "name": "_serviceRegistry", + "type": "address" + }, + { + "internalType": "address", + "name": "_serviceRegistryTokenUtility", + "type": "address" + }, + { + "internalType": "address", + "name": "_operatorWhitelist", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "operator", + "type": "address" + } + ], + "name": "AgentInstanceRegistered", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "serviceId", + "type": "uint256" + } + ], + "name": "AgentInstancesSlotsFilled", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "agentId", + "type": "uint256" + } + ], + "name": "AgentNotFound", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "agentId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "serviceId", + "type": "uint256" + } + ], + "name": "AgentNotInService", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "componentId", + "type": "uint256" + } + ], + "name": "ComponentNotFound", + "type": "error" + }, + { + "inputs": [], + "name": "HashExists", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "operator", + "type": "address" + }, + { + "internalType": "bytes32", + "name": "msgHash", + "type": "bytes32" + }, + { + "internalType": "bytes", + "name": "signature", + "type": "bytes" + } + ], + "name": "HashNotApproved", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "operator", + "type": "address" + }, + { + "internalType": "bytes32", + "name": "msgHash", + "type": "bytes32" + }, + { + "internalType": "bytes", + "name": "signature", + "type": "bytes" + } + ], + "name": "HashNotValidated", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "sent", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "expected", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "serviceId", + "type": "uint256" + } + ], + "name": "IncorrectAgentBondingValue", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "sent", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "expected", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "serviceId", + "type": "uint256" + } + ], + "name": "IncorrectRegistrationDepositValue", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "signature", + "type": "bytes" + }, + { + "internalType": "uint256", + "name": "provided", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "expected", + "type": "uint256" + } + ], + "name": "IncorrectSignatureLength", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "internalType": "address", + "name": "manager", + "type": "address" + } + ], + "name": "ManagerOnly", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "provided", + "type": "address" + }, + { + "internalType": "address", + "name": "expected", + "type": "address" + }, + { + "internalType": "uint256", + "name": "serviceId", + "type": "uint256" + } + ], + "name": "OnlyOwnServiceMultisig", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "operator", + "type": "address" + }, + { + "internalType": "uint256", + "name": "serviceId", + "type": "uint256" + } + ], + "name": "OperatorHasNoInstances", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "provided", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "max", + "type": "uint256" + } + ], + "name": "Overflow", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "internalType": "address", + "name": "owner", + "type": "address" + } + ], + "name": "OwnerOnly", + "type": "error" + }, + { + "inputs": [], + "name": "Paused", + "type": "error" + }, + { + "inputs": [], + "name": "ReentrancyGuard", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "serviceId", + "type": "uint256" + } + ], + "name": "ServiceMustBeInactive", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "TransferFailed", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "multisig", + "type": "address" + } + ], + "name": "UnauthorizedMultisig", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "agentId", + "type": "uint256" + } + ], + "name": "WrongAgentId", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "numValues1", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "numValues2", + "type": "uint256" + } + ], + "name": "WrongArrayLength", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "serviceId", + "type": "uint256" + } + ], + "name": "WrongOperator", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "provided", + "type": "address" + }, + { + "internalType": "address", + "name": "expected", + "type": "address" + } + ], + "name": "WrongOperatorAddress", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "state", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "serviceId", + "type": "uint256" + } + ], + "name": "WrongServiceState", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "currentThreshold", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "minThreshold", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "maxThreshold", + "type": "uint256" + } + ], + "name": "WrongThreshold", + "type": "error" + }, + { + "inputs": [], + "name": "ZeroAddress", + "type": "error" + }, + { + "inputs": [], + "name": "ZeroOperatorAddress", + "type": "error" + }, + { + "inputs": [], + "name": "ZeroValue", + "type": "error" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "multisig", + "type": "address" + } + ], + "name": "CreateMultisig", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "operator", + "type": "address" + }, + { + "indexed": false, + "internalType": "bytes32", + "name": "hash", + "type": "bytes32" + } + ], + "name": "OperatorHashApproved", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "operatorWhitelist", + "type": "address" + } + ], + "name": "OperatorWhitelistUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + } + ], + "name": "OwnerUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + } + ], + "name": "Pause", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + } + ], + "name": "Unpause", + "type": "event" + }, + { + "inputs": [], + "name": "BOND_WRAPPER", + "outputs": [ + { + "internalType": "uint96", + "name": "", + "type": "uint96" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "DOMAIN_SEPARATOR_TYPE_HASH", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "ETH_TOKEN_ADDRESS", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "REGISTER_AGENTS_TYPE_HASH", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "UNBOND_TYPE_HASH", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "serviceId", + "type": "uint256" + } + ], + "name": "activateRegistration", + "outputs": [ + { + "internalType": "bool", + "name": "success", + "type": "bool" + } + ], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [], + "name": "chainId", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "changeOwner", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "serviceOwner", + "type": "address" + }, + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "bytes32", + "name": "configHash", + "type": "bytes32" + }, + { + "internalType": "uint32[]", + "name": "agentIds", + "type": "uint32[]" + }, + { + "components": [ + { + "internalType": "uint32", + "name": "slots", + "type": "uint32" + }, + { + "internalType": "uint96", + "name": "bond", + "type": "uint96" + } + ], + "internalType": "struct IService.AgentParams[]", + "name": "agentParams", + "type": "tuple[]" + }, + { + "internalType": "uint32", + "name": "threshold", + "type": "uint32" + } + ], + "name": "create", + "outputs": [ + { + "internalType": "uint256", + "name": "serviceId", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "serviceId", + "type": "uint256" + }, + { + "internalType": "address", + "name": "multisigImplementation", + "type": "address" + }, + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + } + ], + "name": "deploy", + "outputs": [ + { + "internalType": "address", + "name": "multisig", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "domainSeparator", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getDomainSeparator", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "operator", + "type": "address" + }, + { + "internalType": "uint256", + "name": "serviceId", + "type": "uint256" + } + ], + "name": "getOperatorRegisterAgentsNonce", + "outputs": [ + { + "internalType": "uint256", + "name": "nonce", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "operator", + "type": "address" + }, + { + "internalType": "uint256", + "name": "serviceId", + "type": "uint256" + } + ], + "name": "getOperatorUnbondNonce", + "outputs": [ + { + "internalType": "uint256", + "name": "nonce", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "operator", + "type": "address" + }, + { + "internalType": "address", + "name": "serviceOwner", + "type": "address" + }, + { + "internalType": "uint256", + "name": "serviceId", + "type": "uint256" + }, + { + "internalType": "address[]", + "name": "agentInstances", + "type": "address[]" + }, + { + "internalType": "uint32[]", + "name": "agentIds", + "type": "uint32[]" + }, + { + "internalType": "uint256", + "name": "nonce", + "type": "uint256" + } + ], + "name": "getRegisterAgentsHash", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "operator", + "type": "address" + }, + { + "internalType": "address", + "name": "serviceOwner", + "type": "address" + }, + { + "internalType": "uint256", + "name": "serviceId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "nonce", + "type": "uint256" + } + ], + "name": "getUnbondHash", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "operator", + "type": "address" + }, + { + "internalType": "bytes32", + "name": "hash", + "type": "bytes32" + } + ], + "name": "isOperatorHashApproved", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + }, + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "name": "mapOperatorApprovedHashes", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "mapOperatorRegisterAgentsNonces", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "mapOperatorUnbondNonces", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "name", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "nameHash", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "hash", + "type": "bytes32" + } + ], + "name": "operatorApproveHash", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "operatorWhitelist", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "owner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "pause", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "paused", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "serviceId", + "type": "uint256" + }, + { + "internalType": "address[]", + "name": "agentInstances", + "type": "address[]" + }, + { + "internalType": "uint32[]", + "name": "agentIds", + "type": "uint32[]" + } + ], + "name": "registerAgents", + "outputs": [ + { + "internalType": "bool", + "name": "success", + "type": "bool" + } + ], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "operator", + "type": "address" + }, + { + "internalType": "uint256", + "name": "serviceId", + "type": "uint256" + }, + { + "internalType": "address[]", + "name": "agentInstances", + "type": "address[]" + }, + { + "internalType": "uint32[]", + "name": "agentIds", + "type": "uint32[]" + }, + { + "internalType": "bytes", + "name": "signature", + "type": "bytes" + } + ], + "name": "registerAgentsWithSignature", + "outputs": [ + { + "internalType": "bool", + "name": "success", + "type": "bool" + } + ], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [], + "name": "serviceRegistry", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "serviceRegistryTokenUtility", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newOperatorWhitelist", + "type": "address" + } + ], + "name": "setOperatorWhitelist", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "serviceId", + "type": "uint256" + } + ], + "name": "terminate", + "outputs": [ + { + "internalType": "bool", + "name": "success", + "type": "bool" + }, + { + "internalType": "uint256", + "name": "refund", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "serviceId", + "type": "uint256" + } + ], + "name": "unbond", + "outputs": [ + { + "internalType": "bool", + "name": "success", + "type": "bool" + }, + { + "internalType": "uint256", + "name": "refund", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "operator", + "type": "address" + }, + { + "internalType": "uint256", + "name": "serviceId", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "signature", + "type": "bytes" + } + ], + "name": "unbondWithSignature", + "outputs": [ + { + "internalType": "bool", + "name": "success", + "type": "bool" + }, + { + "internalType": "uint256", + "name": "refund", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "unpause", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "bytes32", + "name": "configHash", + "type": "bytes32" + }, + { + "internalType": "uint32[]", + "name": "agentIds", + "type": "uint32[]" + }, + { + "components": [ + { + "internalType": "uint32", + "name": "slots", + "type": "uint32" + }, + { + "internalType": "uint96", + "name": "bond", + "type": "uint96" + } + ], + "internalType": "struct IService.AgentParams[]", + "name": "agentParams", + "type": "tuple[]" + }, + { + "internalType": "uint32", + "name": "threshold", + "type": "uint32" + }, + { + "internalType": "uint256", + "name": "serviceId", + "type": "uint256" + } + ], + "name": "update", + "outputs": [ + { + "internalType": "bool", + "name": "success", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "version", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "versionHash", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + } + ], + "bytecode": "0x6101406040523480156200001257600080fd5b506040516200365e3803806200365e8339810160408190526200003591620001cf565b6040518060400160405280601581526020017f53657276696365204d616e6167657220546f6b656e000000000000000000000081525060405180604001604052806005815260200164312e312e3160d81b81525081600190816200009a9190620002be565b506002620000a98282620002be565b50815160208084019190912060c05281519082012060e0524660a0526200013160c0805160e051604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60208201529081019290925260608201524660808201523060a08201526000910160405160208183030381529060405280519060200120905090565b60805250506001600160a01b03831615806200015457506001600160a01b038216155b15620001735760405163d92e233d60e01b815260040160405180910390fd5b6001600160a01b03928316610100529082166101205260068054919092166001600160a01b03199182161790915560008054909116331790556200038a565b80516001600160a01b0381168114620001ca57600080fd5b919050565b600080600060608486031215620001e557600080fd5b620001f084620001b2565b92506200020060208501620001b2565b91506200021060408501620001b2565b90509250925092565b634e487b7160e01b600052604160045260246000fd5b600181811c908216806200024457607f821691505b6020821081036200026557634e487b7160e01b600052602260045260246000fd5b50919050565b601f821115620002b957600081815260208120601f850160051c81016020861015620002945750805b601f850160051c820191505b81811015620002b557828155600101620002a0565b5050505b505050565b81516001600160401b03811115620002da57620002da62000219565b620002f281620002eb84546200022f565b846200026b565b602080601f8311600181146200032a5760008415620003115750858301515b600019600386901b1c1916600185901b178555620002b5565b600085815260208120601f198616915b828110156200035b578886015182559484019460019091019084016200033a565b50858210156200037a5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b60805160a05160c05160e05161010051610120516131b9620004a56000396000818161042001528181610bc301528181610dcb01528181611030015281816111ec01528181611532015281816119a101528181611c0701528181611d420152612201015260008181610749015281816109c401528181610aa301528181610c4701528181610d0f01528181610e5701528181610ee8015281816110c80152818161127d01528181611318015281816115e00152818161190601528181611b6b01528181611dc801528181611e9001528181611faa015261216701526000818161033c01526122ea01526000818161083901526122c2015260008181610699015261226e0152600081816108a1015261234301526131b96000f3fe6080604052600436106102a05760003560e01c8063757b11561161016e578063cbcf252a116100cb578063e5da07531161007f578063f172a4ce11610064578063f172a4ce14610827578063f5dcb7bb1461085b578063f698da251461088f57600080fd5b8063e5da0753146107f2578063ed24911d1461081257600080fd5b8063d03ca40a116100b0578063d03ca40a1461078b578063dc1d95251461079e578063e42cdd7c146107d257600080fd5b8063cbcf252a14610737578063cbf994f81461076b57600080fd5b80639488791111610122578063a2e2ad7e11610107578063a2e2ad7e146106bb578063a6a7187f146106f7578063a6f9dae11461071757600080fd5b806394887911146106535780639a8a05921461068757600080fd5b80638456cb59116101535780638456cb59146105f15780638a39fa16146106065780638da5cb5b1461063357600080fd5b8063757b1156146105b15780637a828b28146105d157600080fd5b806328f223421161021c5780635405ecb9116101d057806356bda507116101b557806356bda50714610543578063599be46f146105705780635c975abb1461059057600080fd5b80635405ecb9146104f257806354fd4d501461052e57600080fd5b80633f4ba83a116102015780633f4ba83a1461049d57806341b60677146104b25780634d5a5827146104df57600080fd5b806328f22342146104425780633af5d04e1461046257600080fd5b80631878d1f11161027357806321561bfc1161025857806321561bfc146103b757806327de9e32146103d7578063287140511461040e57600080fd5b80631878d1f11461036c5780631ee81fb51461039457600080fd5b806306fdde03146102a557806307a3e0a8146102d05780630d0d57a8146102f2578063152b5c0f1461032a575b600080fd5b3480156102b157600080fd5b506102ba6108c3565b6040516102c79190612620565b60405180910390f35b3480156102dc57600080fd5b506102f06102eb36600461263a565b610951565b005b3480156102fe57600080fd5b5061031261030d36600461274b565b6109aa565b6040516001600160a01b0390911681526020016102c7565b34801561033657600080fd5b5061035e7f000000000000000000000000000000000000000000000000000000000000000081565b6040519081526020016102c7565b34801561037857600080fd5b5061031273eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee81565b6103a76103a23660046128ac565b610a80565b60405190151581526020016102c7565b3480156103c357600080fd5b50600654610312906001600160a01b031681565b3480156103e357600080fd5b506103f76103f236600461263a565b610da0565b6040805192151583526020830191909152016102c7565b34801561041a57600080fd5b506103127f000000000000000000000000000000000000000000000000000000000000000081565b34801561044e57600080fd5b506103f761045d366004612951565b610ee1565b34801561046e57600080fd5b506103a761047d366004612994565b600560209081526000928352604080842090915290825290205460ff1681565b3480156104a957600080fd5b506102f0611152565b3480156104be57600080fd5b5061035e6104cd36600461263a565b60046020526000908152604090205481565b6103a76104ed36600461263a565b6111c9565b3480156104fe57600080fd5b5061035e61050d366004612994565b60a01b6001600160a01b039091161760009081526003602052604090205490565b34801561053a57600080fd5b506102ba611398565b34801561054f57600080fd5b50610558600181565b6040516001600160601b0390911681526020016102c7565b34801561057c57600080fd5b506102f061058b3660046129c0565b6113a5565b34801561059c57600080fd5b506000546103a790600160a01b900460ff1681565b3480156105bd57600080fd5b5061035e6105cc3660046129dd565b61143c565b3480156105dd57600080fd5b506103f76105ec36600461263a565b61152b565b3480156105fd57600080fd5b506102f0611617565b34801561061257600080fd5b5061035e61062136600461263a565b60036020526000908152604090205481565b34801561063f57600080fd5b50600054610312906001600160a01b031681565b34801561065f57600080fd5b5061035e7f92b2008d2a99f26809ac9d1989fe92334aa84124767331997ba0eec16050ecf481565b34801561069357600080fd5b5061035e7f000000000000000000000000000000000000000000000000000000000000000081565b3480156106c757600080fd5b5061035e6106d6366004612994565b60a01b6001600160a01b039091161760009081526004602052604090205490565b34801561070357600080fd5b5061035e610712366004612a78565b611694565b34801561072357600080fd5b506102f06107323660046129c0565b611750565b34801561074357600080fd5b506103127f000000000000000000000000000000000000000000000000000000000000000081565b34801561077757600080fd5b506103a7610786366004612b5a565b61180c565b6103a7610799366004612bf3565b611c81565b3480156107aa57600080fd5b5061035e7fde64b4c9fac43e1615e938b03573b078604f57b4d2e78d3a27d7b20ba017e12681565b3480156107de57600080fd5b5061035e6107ed366004612c56565b611f1b565b3480156107fe57600080fd5b506103a761080d366004612994565b61223c565b34801561081e57600080fd5b5061035e61226a565b34801561083357600080fd5b5061035e7f000000000000000000000000000000000000000000000000000000000000000081565b34801561086757600080fd5b5061035e7f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f81565b34801561089b57600080fd5b5061035e7f000000000000000000000000000000000000000000000000000000000000000081565b600180546108d090612cf8565b80601f01602080910402602001604051908101604052809291908181526020018280546108fc90612cf8565b80156109495780601f1061091e57610100808354040283529160200191610949565b820191906000526020600020905b81548152906001019060200180831161092c57829003601f168201915b505050505081565b336000818152600560209081526040808320858452825291829020805460ff1916600117905590518381527f85eb1f050732417c0566422b6004a6c5cbded9ded1a406de04060719af52a13a910160405180910390a250565b60405163f908bc7760e01b81526000906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063f908bc77906109ff903390889088908890600401612d2c565b6020604051808303816000875af1158015610a1e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a429190612d5e565b6040519091506001600160a01b038216907fec97633905b1dbe9773a7536e9a986dcf89803e1193934b7b6d76587c68beb4090600090a29392505050565b6040516331a9108f60e11b81526004810185905260009081906001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690636352211e90602401602060405180830381865afa158015610aea573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b0e9190612d5e565b9050336001600160a01b03821614610b4f5760405163521eb56d60e11b81523360048201526001600160a01b03821660248201526044015b60405180910390fd5b60a086901b6001600160a01b0388161760008181526004602052604081205490610b7d8a858b8b8b8761143c565b9050610b8a8a8288612365565b81610b9481612d91565b60008581526004602081905260408083208490555163dc4f8bc560e01b81529295509092506001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169163dc4f8bc591610bfa918f918f918e9101612deb565b6020604051808303816000875af1158015610c19573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c3d9190612e2c565b90508015610cf8577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663dff7672460016001600160601b03168b51610c8b9190612e47565b8d8d8d8d6040518663ffffffff1660e01b8152600401610cae9493929190612e97565b60206040518083038185885af1158015610ccc573d6000803e3d6000fd5b50505050506040513d601f19601f82011682018060405250810190610cf19190612e2c565b9550610d92565b6040516337fdd9c960e21b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063dff76724903490610d4c908f908f908f908f90600401612e97565b60206040518083038185885af1158015610d6a573d6000803e3d6000fd5b50505050506040513d601f19601f82011682018060405250810190610d8f9190612e2c565b95505b505050505095945050505050565b60405163161e984960e31b815233600482015260248101829052600090819081906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063b0f4c248906044016020604051808303816000875af1158015610e14573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e389190612edc565b6040516352e82ce560e11b8152336004820152602481018690529091507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063a5d059ca906044015b60408051808303816000875af1158015610ea8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ecc9190612ef5565b90935091508015610edb578091505b50915091565b60008060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316636352211e866040518263ffffffff1660e01b8152600401610f3491815260200190565b602060405180830381865afa158015610f51573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f759190612d5e565b9050336001600160a01b03821614610fb15760405163521eb56d60e11b81523360048201526001600160a01b0382166024820152604401610b46565b60a085901b6001600160a01b0387161760008181526003602052604081205490610fdd89858a85611694565b9050610fea898289612365565b81610ff481612d91565b6000858152600360205260408082208390555163161e984960e31b81526001600160a01b038d81166004830152602482018d90529295509092507f00000000000000000000000000000000000000000000000000000000000000009091169063b0f4c248906044016020604051808303816000875af115801561107b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061109f9190612edc565b6040516352e82ce560e11b81526001600160a01b038c81166004830152602482018c90529192507f00000000000000000000000000000000000000000000000000000000000000009091169063a5d059ca9060440160408051808303816000875af1158015611112573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111369190612ef5565b90975095508015611145578095505b5050505050935093915050565b6000546001600160a01b031633146111925760005460405163521eb56d60e11b81523360048201526001600160a01b039091166024820152604401610b46565b6000805460ff60a01b1916815560405133917faeb196d352664784d1900b0e7414a8face7d29f4dae8c4b0cf68ed477423bbf491a2565b60405163542db44960e01b81526004810182905260009081906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063542db449906024016020604051808303816000875af1158015611235573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112599190612e2c565b905080156112fc5760405163388fdbed60e21b8152336004820152602481018490527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063e23f6fb49060019060440160206040518083038185885af11580156112d0573d6000803e3d6000fd5b50505050506040513d601f19601f820116820180604052508101906112f59190612e2c565b9150611392565b60405163388fdbed60e21b8152336004820152602481018490527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063e23f6fb490349060440160206040518083038185885af115801561136a573d6000803e3d6000fd5b50505050506040513d601f19601f8201168201806040525081019061138f9190612e2c565b91505b50919050565b600280546108d090612cf8565b6000546001600160a01b031633146113e55760005460405163521eb56d60e11b81523360048201526001600160a01b039091166024820152604401610b46565b6006805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b0383169081179091556040517ff8e76e8a7c35558598a944d509f1ed32b104e77b1098ef1dfa5b97b86b09df8f90600090a250565b600061144661226a565b7fde64b4c9fac43e1615e938b03573b078604f57b4d2e78d3a27d7b20ba017e126888888888860405160200161147d929190612f21565b60408051601f198184030181528282528051602091820120908301969096526001600160a01b0394851690820152929091166060830152608082015260a081019190915260c0810184905260e0016040516020818303038152906040528051906020012060405160200161150892919061190160f01b81526002810192909252602282015260420190565b6040516020818303038152906040528051906020012090505b9695505050505050565b60008060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166325e1afc3856040518263ffffffff1660e01b815260040161157e91815260200190565b6020604051808303816000875af115801561159d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115c19190612edc565b60405163ccc9305d60e01b8152336004820152602481018690529091507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063ccc9305d90604401610e8a565b6000546001600160a01b031633146116575760005460405163521eb56d60e11b81523360048201526001600160a01b039091166024820152604401610b46565b6000805460ff60a01b1916600160a01b17815560405133917f5ee71a369c8672edded508e624ffc9257fa1ae6886ef32905c18e60196bca39991a2565b600061169e61226a565b604080517f92b2008d2a99f26809ac9d1989fe92334aa84124767331997ba0eec16050ecf460208201526001600160a01b038089169282019290925290861660608201526080810185905260a0810184905260c0016040516020818303038152906040528051906020012060405160200161173092919061190160f01b81526002810192909252602282015260420190565b604051602081830303815290604052805190602001209050949350505050565b6000546001600160a01b031633146117905760005460405163521eb56d60e11b81523360048201526001600160a01b039091166024820152604401610b46565b6001600160a01b0381166117b75760405163d92e233d60e01b815260040160405180910390fd5b6000805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b038316908117825560405190917f4ffd725fc4a22075e9ec71c59edf9c38cdeb588a91b24fc5b61388c5be41282b91a250565b60006001600160a01b0387166118355760405163d92e233d60e01b815260040160405180910390fd5b835173eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed196001600160a01b03891601611a0a5760005b818110156118ee57600086828151811061187b5761187b612f46565b60200260200101516000015163ffffffff161180156118c057508581815181106118a7576118a7612f46565b6020026020010151602001516001600160601b03166000145b156118de57604051637c946ed760e01b815260040160405180910390fd5b6118e781612d91565b905061185f565b5060405163197f329f60e31b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063cbf994f8906119459033908b908b908b908b908b90600401612fa6565b6020604051808303816000875af1158015611964573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119889190612e2c565b604051630be6cc4b60e31b8152600481018590529092507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690635f36625890602401600060405180830381600087803b1580156119ed57600080fd5b505af1158015611a01573d6000803e3d6000fd5b50505050611c76565b60008167ffffffffffffffff811115611a2557611a2561266b565b604051908082528060200260200182016040528015611a4e578160200160208202803683370190505b50905060005b82811015611b53576000878281518110611a7057611a70612f46565b60200260200101516000015163ffffffff161115611b4357868181518110611a9a57611a9a612f46565b6020026020010151602001516001600160601b0316600003611acf57604051637c946ed760e01b815260040160405180910390fd5b868181518110611ae157611ae1612f46565b6020026020010151602001516001600160601b0316828281518110611b0857611b08612f46565b6020026020010181815250506001878281518110611b2857611b28612f46565b6020908102919091018101516001600160601b039092169101525b611b4c81612d91565b9050611a54565b5060405163197f329f60e31b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063cbf994f890611baa9033908c908c908c908c908c90600401612fa6565b6020604051808303816000875af1158015611bc9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611bed9190612e2c565b6040516338f3a6a160e21b81529093506001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063e3ce9a8490611c429087908d908c908790600401612ffc565b600060405180830381600087803b158015611c5c57600080fd5b505af1158015611c70573d6000803e3d6000fd5b50505050505b509695505050505050565b6006546000906001600160a01b031615611d28576006546040516356a7b60760e01b8152600481018690523360248201526001600160a01b03909116906356a7b60790604401602060405180830381865afa158015611ce4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d089190612e2c565b611d28576040516322ddebd960e21b815260048101859052602401610b46565b60405163dc4f8bc560e01b81526000906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063dc4f8bc590611d7b90339089908890600401612deb565b6020604051808303816000875af1158015611d9a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611dbe9190612e2c565b90508015611e79577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663dff7672460016001600160601b03168651611e0c9190612e47565b338888886040518663ffffffff1660e01b8152600401611e2f9493929190612e97565b60206040518083038185885af1158015611e4d573d6000803e3d6000fd5b50505050506040513d601f19601f82011682018060405250810190611e729190612e2c565b9150611f13565b6040516337fdd9c960e21b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063dff76724903490611ecd9033908a908a908a90600401612e97565b60206040518083038185885af1158015611eeb573d6000803e3d6000fd5b50505050506040513d601f19601f82011682018060405250810190611f109190612e2c565b91505b509392505050565b60008054600160a01b900460ff1615611f47576040516313d0ff5960e31b815260040160405180910390fd5b6001600160a01b038616611f6e5760405163d92e233d60e01b815260040160405180910390fd5b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed196001600160a01b038716016120315760405163fbdeb3d760e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063fbdeb3d790611fe7908a908990899089908990600401613067565b6020604051808303816000875af1158015612006573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061202a9190612edc565b9050611521565b825160008167ffffffffffffffff81111561204e5761204e61266b565b604051908082528060200260200182016040528015612077578160200160208202803683370190505b50905060005b8281101561214f5785818151811061209757612097612f46565b6020026020010151602001516001600160601b03166000036120cc57604051637c946ed760e01b815260040160405180910390fd5b8581815181106120de576120de612f46565b6020026020010151602001516001600160601b031682828151811061210557612105612f46565b602002602001018181525050600186828151811061212557612125612f46565b6020908102919091018101516001600160601b0390921691015261214881612d91565b905061207d565b5060405163fbdeb3d760e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063fbdeb3d7906121a4908c908b908b908b908b90600401613067565b6020604051808303816000875af11580156121c3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121e79190612edc565b6040516338f3a6a160e21b81529093506001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063e3ce9a8490611c429086908c908b908790600401612ffc565b6001600160a01b038216600090815260056020908152604080832084845290915290205460ff165b92915050565b60007f000000000000000000000000000000000000000000000000000000000000000046146123405761233b604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60208201527f0000000000000000000000000000000000000000000000000000000000000000918101919091527f000000000000000000000000000000000000000000000000000000000000000060608201524660808201523060a082015260009060c00160405160208183030381529060405280519060200120905090565b905090565b507f000000000000000000000000000000000000000000000000000000000000000090565b6001600160a01b03831661238c5760405163e63f571f60e01b815260040160405180910390fd5b80516041146123b5578051604051631d9f5a5f60e01b8152610b469183916041906004016130ba565b6000816040815181106123ca576123ca612f46565b016020015160f81c90506004811080156123ec57506001600160a01b0384163b155b156123ff576123fc601b826130df565b90505b60208201516040830151600060ff84166004036124d45750604051630b135d3f60e11b80825283916001600160a01b03831690631626ba7e90612448908a908a906004016130f8565b602060405180830381865afa158015612465573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124899190613119565b7fffffffff0000000000000000000000000000000000000000000000000000000016146124cf5780868660405163694d54dd60e01b8152600401610b469392919061315b565b61258c565b8360ff1660050361252c57506001600160a01b0382166000908152600560209081526040808320888452909152902054829060ff166124cf578086866040516312cf832560e01b8152600401610b469392919061315b565b60408051600081526020810180835288905260ff861691810191909152606081018490526080810183905260019060a0016020604051602081039080840390855afa15801561257f573d6000803e3d6000fd5b5050506020604051035190505b866001600160a01b0316816001600160a01b0316146125d15760405163a806216d60e01b81526001600160a01b03808316600483015288166024820152604401610b46565b50505050505050565b6000815180845260005b81811015612600576020818501810151868301820152016125e4565b506000602082860101526020601f19601f83011685010191505092915050565b60208152600061263360208301846125da565b9392505050565b60006020828403121561264c57600080fd5b5035919050565b6001600160a01b038116811461266857600080fd5b50565b634e487b7160e01b600052604160045260246000fd5b6040805190810167ffffffffffffffff811182821017156126a4576126a461266b565b60405290565b604051601f8201601f1916810167ffffffffffffffff811182821017156126d3576126d361266b565b604052919050565b600082601f8301126126ec57600080fd5b813567ffffffffffffffff8111156127065761270661266b565b612719601f8201601f19166020016126aa565b81815284602083860101111561272e57600080fd5b816020850160208301376000918101602001919091529392505050565b60008060006060848603121561276057600080fd5b83359250602084013561277281612653565b9150604084013567ffffffffffffffff81111561278e57600080fd5b61279a868287016126db565b9150509250925092565b600067ffffffffffffffff8211156127be576127be61266b565b5060051b60200190565b600082601f8301126127d957600080fd5b813560206127ee6127e9836127a4565b6126aa565b82815260059290921b8401810191818101908684111561280d57600080fd5b8286015b84811015611c7657803561282481612653565b8352918301918301612811565b803563ffffffff8116811461284557600080fd5b919050565b600082601f83011261285b57600080fd5b8135602061286b6127e9836127a4565b82815260059290921b8401810191818101908684111561288a57600080fd5b8286015b84811015611c765761289f81612831565b835291830191830161288e565b600080600080600060a086880312156128c457600080fd5b85356128cf81612653565b945060208601359350604086013567ffffffffffffffff808211156128f357600080fd5b6128ff89838a016127c8565b9450606088013591508082111561291557600080fd5b61292189838a0161284a565b9350608088013591508082111561293757600080fd5b50612944888289016126db565b9150509295509295909350565b60008060006060848603121561296657600080fd5b833561297181612653565b925060208401359150604084013567ffffffffffffffff81111561278e57600080fd5b600080604083850312156129a757600080fd5b82356129b281612653565b946020939093013593505050565b6000602082840312156129d257600080fd5b813561263381612653565b60008060008060008060c087890312156129f657600080fd5b8635612a0181612653565b95506020870135612a1181612653565b945060408701359350606087013567ffffffffffffffff80821115612a3557600080fd5b612a418a838b016127c8565b94506080890135915080821115612a5757600080fd5b50612a6489828a0161284a565b92505060a087013590509295509295509295565b60008060008060808587031215612a8e57600080fd5b8435612a9981612653565b93506020850135612aa981612653565b93969395505050506040820135916060013590565b600082601f830112612acf57600080fd5b81356020612adf6127e9836127a4565b82815260069290921b84018101918181019086841115612afe57600080fd5b8286015b84811015611c765760408189031215612b1b5760008081fd5b612b23612681565b612b2c82612831565b8152848201356001600160601b0381168114612b485760008081fd5b81860152835291830191604001612b02565b60008060008060008060c08789031215612b7357600080fd5b8635612b7e81612653565b955060208701359450604087013567ffffffffffffffff80821115612ba257600080fd5b612bae8a838b0161284a565b95506060890135915080821115612bc457600080fd5b50612bd189828a01612abe565b935050612be060808801612831565b915060a087013590509295509295509295565b600080600060608486031215612c0857600080fd5b83359250602084013567ffffffffffffffff80821115612c2757600080fd5b612c33878388016127c8565b93506040860135915080821115612c4957600080fd5b5061279a8682870161284a565b60008060008060008060c08789031215612c6f57600080fd5b8635612c7a81612653565b95506020870135612c8a81612653565b945060408701359350606087013567ffffffffffffffff80821115612cae57600080fd5b612cba8a838b0161284a565b94506080890135915080821115612cd057600080fd5b50612cdd89828a01612abe565b925050612cec60a08801612831565b90509295509295509295565b600181811c90821680612d0c57607f821691505b60208210810361139257634e487b7160e01b600052602260045260246000fd5b60006001600160a01b0380871683528560208401528085166040840152506080606083015261152160808301846125da565b600060208284031215612d7057600080fd5b815161263381612653565b634e487b7160e01b600052601160045260246000fd5b600060018201612da357612da3612d7b565b5060010190565b600081518084526020808501945080840160005b83811015612de057815163ffffffff1687529582019590820190600101612dbe565b509495945050505050565b6001600160a01b0384168152826020820152606060408201526000612e136060830184612daa565b95945050505050565b8051801515811461284557600080fd5b600060208284031215612e3e57600080fd5b61263382612e1c565b808202811582820484141761226457612264612d7b565b600081518084526020808501945080840160005b83811015612de05781516001600160a01b031687529582019590820190600101612e72565b6001600160a01b0385168152836020820152608060408201526000612ebf6080830185612e5e565b8281036060840152612ed18185612daa565b979650505050505050565b600060208284031215612eee57600080fd5b5051919050565b60008060408385031215612f0857600080fd5b612f1183612e1c565b9150602083015190509250929050565b604081526000612f346040830185612e5e565b8281036020840152611f108185612daa565b634e487b7160e01b600052603260045260246000fd5b600081518084526020808501945080840160005b83811015612de0578151805163ffffffff1688528301516001600160601b03168388015260409096019590820190600101612f70565b6001600160a01b038716815285602082015260c060408201526000612fce60c0830187612daa565b8281036060840152612fe08187612f5c565b63ffffffff959095166080840152505060a00152949350505050565b848152600060206001600160a01b03861681840152608060408401526130256080840186612daa565b838103606085015284518082528286019183019060005b818110156130585783518352928401929184019160010161303c565b50909998505050505050505050565b6001600160a01b038616815284602082015260a06040820152600061308f60a0830186612daa565b82810360608401526130a18186612f5c565b91505063ffffffff831660808301529695505050505050565b6060815260006130cd60608301866125da565b60208301949094525060400152919050565b60ff818116838216019081111561226457612264612d7b565b82815260406020820152600061311160408301846125da565b949350505050565b60006020828403121561312b57600080fd5b81517fffffffff000000000000000000000000000000000000000000000000000000008116811461263357600080fd5b6001600160a01b0384168152826020820152606060408201526000612e1360608301846125da56fea2646970667358221220f2d50ac7cf109448ada9fff306a728e5251fe66a1c6e6ec31ba9ad713c2ad83964736f6c63430008130033", + "deployedBytecode": "0x6080604052600436106102a05760003560e01c8063757b11561161016e578063cbcf252a116100cb578063e5da07531161007f578063f172a4ce11610064578063f172a4ce14610827578063f5dcb7bb1461085b578063f698da251461088f57600080fd5b8063e5da0753146107f2578063ed24911d1461081257600080fd5b8063d03ca40a116100b0578063d03ca40a1461078b578063dc1d95251461079e578063e42cdd7c146107d257600080fd5b8063cbcf252a14610737578063cbf994f81461076b57600080fd5b80639488791111610122578063a2e2ad7e11610107578063a2e2ad7e146106bb578063a6a7187f146106f7578063a6f9dae11461071757600080fd5b806394887911146106535780639a8a05921461068757600080fd5b80638456cb59116101535780638456cb59146105f15780638a39fa16146106065780638da5cb5b1461063357600080fd5b8063757b1156146105b15780637a828b28146105d157600080fd5b806328f223421161021c5780635405ecb9116101d057806356bda507116101b557806356bda50714610543578063599be46f146105705780635c975abb1461059057600080fd5b80635405ecb9146104f257806354fd4d501461052e57600080fd5b80633f4ba83a116102015780633f4ba83a1461049d57806341b60677146104b25780634d5a5827146104df57600080fd5b806328f22342146104425780633af5d04e1461046257600080fd5b80631878d1f11161027357806321561bfc1161025857806321561bfc146103b757806327de9e32146103d7578063287140511461040e57600080fd5b80631878d1f11461036c5780631ee81fb51461039457600080fd5b806306fdde03146102a557806307a3e0a8146102d05780630d0d57a8146102f2578063152b5c0f1461032a575b600080fd5b3480156102b157600080fd5b506102ba6108c3565b6040516102c79190612620565b60405180910390f35b3480156102dc57600080fd5b506102f06102eb36600461263a565b610951565b005b3480156102fe57600080fd5b5061031261030d36600461274b565b6109aa565b6040516001600160a01b0390911681526020016102c7565b34801561033657600080fd5b5061035e7f000000000000000000000000000000000000000000000000000000000000000081565b6040519081526020016102c7565b34801561037857600080fd5b5061031273eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee81565b6103a76103a23660046128ac565b610a80565b60405190151581526020016102c7565b3480156103c357600080fd5b50600654610312906001600160a01b031681565b3480156103e357600080fd5b506103f76103f236600461263a565b610da0565b6040805192151583526020830191909152016102c7565b34801561041a57600080fd5b506103127f000000000000000000000000000000000000000000000000000000000000000081565b34801561044e57600080fd5b506103f761045d366004612951565b610ee1565b34801561046e57600080fd5b506103a761047d366004612994565b600560209081526000928352604080842090915290825290205460ff1681565b3480156104a957600080fd5b506102f0611152565b3480156104be57600080fd5b5061035e6104cd36600461263a565b60046020526000908152604090205481565b6103a76104ed36600461263a565b6111c9565b3480156104fe57600080fd5b5061035e61050d366004612994565b60a01b6001600160a01b039091161760009081526003602052604090205490565b34801561053a57600080fd5b506102ba611398565b34801561054f57600080fd5b50610558600181565b6040516001600160601b0390911681526020016102c7565b34801561057c57600080fd5b506102f061058b3660046129c0565b6113a5565b34801561059c57600080fd5b506000546103a790600160a01b900460ff1681565b3480156105bd57600080fd5b5061035e6105cc3660046129dd565b61143c565b3480156105dd57600080fd5b506103f76105ec36600461263a565b61152b565b3480156105fd57600080fd5b506102f0611617565b34801561061257600080fd5b5061035e61062136600461263a565b60036020526000908152604090205481565b34801561063f57600080fd5b50600054610312906001600160a01b031681565b34801561065f57600080fd5b5061035e7f92b2008d2a99f26809ac9d1989fe92334aa84124767331997ba0eec16050ecf481565b34801561069357600080fd5b5061035e7f000000000000000000000000000000000000000000000000000000000000000081565b3480156106c757600080fd5b5061035e6106d6366004612994565b60a01b6001600160a01b039091161760009081526004602052604090205490565b34801561070357600080fd5b5061035e610712366004612a78565b611694565b34801561072357600080fd5b506102f06107323660046129c0565b611750565b34801561074357600080fd5b506103127f000000000000000000000000000000000000000000000000000000000000000081565b34801561077757600080fd5b506103a7610786366004612b5a565b61180c565b6103a7610799366004612bf3565b611c81565b3480156107aa57600080fd5b5061035e7fde64b4c9fac43e1615e938b03573b078604f57b4d2e78d3a27d7b20ba017e12681565b3480156107de57600080fd5b5061035e6107ed366004612c56565b611f1b565b3480156107fe57600080fd5b506103a761080d366004612994565b61223c565b34801561081e57600080fd5b5061035e61226a565b34801561083357600080fd5b5061035e7f000000000000000000000000000000000000000000000000000000000000000081565b34801561086757600080fd5b5061035e7f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f81565b34801561089b57600080fd5b5061035e7f000000000000000000000000000000000000000000000000000000000000000081565b600180546108d090612cf8565b80601f01602080910402602001604051908101604052809291908181526020018280546108fc90612cf8565b80156109495780601f1061091e57610100808354040283529160200191610949565b820191906000526020600020905b81548152906001019060200180831161092c57829003601f168201915b505050505081565b336000818152600560209081526040808320858452825291829020805460ff1916600117905590518381527f85eb1f050732417c0566422b6004a6c5cbded9ded1a406de04060719af52a13a910160405180910390a250565b60405163f908bc7760e01b81526000906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063f908bc77906109ff903390889088908890600401612d2c565b6020604051808303816000875af1158015610a1e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a429190612d5e565b6040519091506001600160a01b038216907fec97633905b1dbe9773a7536e9a986dcf89803e1193934b7b6d76587c68beb4090600090a29392505050565b6040516331a9108f60e11b81526004810185905260009081906001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690636352211e90602401602060405180830381865afa158015610aea573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b0e9190612d5e565b9050336001600160a01b03821614610b4f5760405163521eb56d60e11b81523360048201526001600160a01b03821660248201526044015b60405180910390fd5b60a086901b6001600160a01b0388161760008181526004602052604081205490610b7d8a858b8b8b8761143c565b9050610b8a8a8288612365565b81610b9481612d91565b60008581526004602081905260408083208490555163dc4f8bc560e01b81529295509092506001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169163dc4f8bc591610bfa918f918f918e9101612deb565b6020604051808303816000875af1158015610c19573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c3d9190612e2c565b90508015610cf8577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663dff7672460016001600160601b03168b51610c8b9190612e47565b8d8d8d8d6040518663ffffffff1660e01b8152600401610cae9493929190612e97565b60206040518083038185885af1158015610ccc573d6000803e3d6000fd5b50505050506040513d601f19601f82011682018060405250810190610cf19190612e2c565b9550610d92565b6040516337fdd9c960e21b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063dff76724903490610d4c908f908f908f908f90600401612e97565b60206040518083038185885af1158015610d6a573d6000803e3d6000fd5b50505050506040513d601f19601f82011682018060405250810190610d8f9190612e2c565b95505b505050505095945050505050565b60405163161e984960e31b815233600482015260248101829052600090819081906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063b0f4c248906044016020604051808303816000875af1158015610e14573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e389190612edc565b6040516352e82ce560e11b8152336004820152602481018690529091507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063a5d059ca906044015b60408051808303816000875af1158015610ea8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ecc9190612ef5565b90935091508015610edb578091505b50915091565b60008060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316636352211e866040518263ffffffff1660e01b8152600401610f3491815260200190565b602060405180830381865afa158015610f51573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f759190612d5e565b9050336001600160a01b03821614610fb15760405163521eb56d60e11b81523360048201526001600160a01b0382166024820152604401610b46565b60a085901b6001600160a01b0387161760008181526003602052604081205490610fdd89858a85611694565b9050610fea898289612365565b81610ff481612d91565b6000858152600360205260408082208390555163161e984960e31b81526001600160a01b038d81166004830152602482018d90529295509092507f00000000000000000000000000000000000000000000000000000000000000009091169063b0f4c248906044016020604051808303816000875af115801561107b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061109f9190612edc565b6040516352e82ce560e11b81526001600160a01b038c81166004830152602482018c90529192507f00000000000000000000000000000000000000000000000000000000000000009091169063a5d059ca9060440160408051808303816000875af1158015611112573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111369190612ef5565b90975095508015611145578095505b5050505050935093915050565b6000546001600160a01b031633146111925760005460405163521eb56d60e11b81523360048201526001600160a01b039091166024820152604401610b46565b6000805460ff60a01b1916815560405133917faeb196d352664784d1900b0e7414a8face7d29f4dae8c4b0cf68ed477423bbf491a2565b60405163542db44960e01b81526004810182905260009081906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063542db449906024016020604051808303816000875af1158015611235573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112599190612e2c565b905080156112fc5760405163388fdbed60e21b8152336004820152602481018490527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063e23f6fb49060019060440160206040518083038185885af11580156112d0573d6000803e3d6000fd5b50505050506040513d601f19601f820116820180604052508101906112f59190612e2c565b9150611392565b60405163388fdbed60e21b8152336004820152602481018490527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063e23f6fb490349060440160206040518083038185885af115801561136a573d6000803e3d6000fd5b50505050506040513d601f19601f8201168201806040525081019061138f9190612e2c565b91505b50919050565b600280546108d090612cf8565b6000546001600160a01b031633146113e55760005460405163521eb56d60e11b81523360048201526001600160a01b039091166024820152604401610b46565b6006805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b0383169081179091556040517ff8e76e8a7c35558598a944d509f1ed32b104e77b1098ef1dfa5b97b86b09df8f90600090a250565b600061144661226a565b7fde64b4c9fac43e1615e938b03573b078604f57b4d2e78d3a27d7b20ba017e126888888888860405160200161147d929190612f21565b60408051601f198184030181528282528051602091820120908301969096526001600160a01b0394851690820152929091166060830152608082015260a081019190915260c0810184905260e0016040516020818303038152906040528051906020012060405160200161150892919061190160f01b81526002810192909252602282015260420190565b6040516020818303038152906040528051906020012090505b9695505050505050565b60008060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166325e1afc3856040518263ffffffff1660e01b815260040161157e91815260200190565b6020604051808303816000875af115801561159d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115c19190612edc565b60405163ccc9305d60e01b8152336004820152602481018690529091507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063ccc9305d90604401610e8a565b6000546001600160a01b031633146116575760005460405163521eb56d60e11b81523360048201526001600160a01b039091166024820152604401610b46565b6000805460ff60a01b1916600160a01b17815560405133917f5ee71a369c8672edded508e624ffc9257fa1ae6886ef32905c18e60196bca39991a2565b600061169e61226a565b604080517f92b2008d2a99f26809ac9d1989fe92334aa84124767331997ba0eec16050ecf460208201526001600160a01b038089169282019290925290861660608201526080810185905260a0810184905260c0016040516020818303038152906040528051906020012060405160200161173092919061190160f01b81526002810192909252602282015260420190565b604051602081830303815290604052805190602001209050949350505050565b6000546001600160a01b031633146117905760005460405163521eb56d60e11b81523360048201526001600160a01b039091166024820152604401610b46565b6001600160a01b0381166117b75760405163d92e233d60e01b815260040160405180910390fd5b6000805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b038316908117825560405190917f4ffd725fc4a22075e9ec71c59edf9c38cdeb588a91b24fc5b61388c5be41282b91a250565b60006001600160a01b0387166118355760405163d92e233d60e01b815260040160405180910390fd5b835173eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed196001600160a01b03891601611a0a5760005b818110156118ee57600086828151811061187b5761187b612f46565b60200260200101516000015163ffffffff161180156118c057508581815181106118a7576118a7612f46565b6020026020010151602001516001600160601b03166000145b156118de57604051637c946ed760e01b815260040160405180910390fd5b6118e781612d91565b905061185f565b5060405163197f329f60e31b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063cbf994f8906119459033908b908b908b908b908b90600401612fa6565b6020604051808303816000875af1158015611964573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119889190612e2c565b604051630be6cc4b60e31b8152600481018590529092507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690635f36625890602401600060405180830381600087803b1580156119ed57600080fd5b505af1158015611a01573d6000803e3d6000fd5b50505050611c76565b60008167ffffffffffffffff811115611a2557611a2561266b565b604051908082528060200260200182016040528015611a4e578160200160208202803683370190505b50905060005b82811015611b53576000878281518110611a7057611a70612f46565b60200260200101516000015163ffffffff161115611b4357868181518110611a9a57611a9a612f46565b6020026020010151602001516001600160601b0316600003611acf57604051637c946ed760e01b815260040160405180910390fd5b868181518110611ae157611ae1612f46565b6020026020010151602001516001600160601b0316828281518110611b0857611b08612f46565b6020026020010181815250506001878281518110611b2857611b28612f46565b6020908102919091018101516001600160601b039092169101525b611b4c81612d91565b9050611a54565b5060405163197f329f60e31b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063cbf994f890611baa9033908c908c908c908c908c90600401612fa6565b6020604051808303816000875af1158015611bc9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611bed9190612e2c565b6040516338f3a6a160e21b81529093506001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063e3ce9a8490611c429087908d908c908790600401612ffc565b600060405180830381600087803b158015611c5c57600080fd5b505af1158015611c70573d6000803e3d6000fd5b50505050505b509695505050505050565b6006546000906001600160a01b031615611d28576006546040516356a7b60760e01b8152600481018690523360248201526001600160a01b03909116906356a7b60790604401602060405180830381865afa158015611ce4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d089190612e2c565b611d28576040516322ddebd960e21b815260048101859052602401610b46565b60405163dc4f8bc560e01b81526000906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063dc4f8bc590611d7b90339089908890600401612deb565b6020604051808303816000875af1158015611d9a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611dbe9190612e2c565b90508015611e79577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663dff7672460016001600160601b03168651611e0c9190612e47565b338888886040518663ffffffff1660e01b8152600401611e2f9493929190612e97565b60206040518083038185885af1158015611e4d573d6000803e3d6000fd5b50505050506040513d601f19601f82011682018060405250810190611e729190612e2c565b9150611f13565b6040516337fdd9c960e21b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063dff76724903490611ecd9033908a908a908a90600401612e97565b60206040518083038185885af1158015611eeb573d6000803e3d6000fd5b50505050506040513d601f19601f82011682018060405250810190611f109190612e2c565b91505b509392505050565b60008054600160a01b900460ff1615611f47576040516313d0ff5960e31b815260040160405180910390fd5b6001600160a01b038616611f6e5760405163d92e233d60e01b815260040160405180910390fd5b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed196001600160a01b038716016120315760405163fbdeb3d760e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063fbdeb3d790611fe7908a908990899089908990600401613067565b6020604051808303816000875af1158015612006573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061202a9190612edc565b9050611521565b825160008167ffffffffffffffff81111561204e5761204e61266b565b604051908082528060200260200182016040528015612077578160200160208202803683370190505b50905060005b8281101561214f5785818151811061209757612097612f46565b6020026020010151602001516001600160601b03166000036120cc57604051637c946ed760e01b815260040160405180910390fd5b8581815181106120de576120de612f46565b6020026020010151602001516001600160601b031682828151811061210557612105612f46565b602002602001018181525050600186828151811061212557612125612f46565b6020908102919091018101516001600160601b0390921691015261214881612d91565b905061207d565b5060405163fbdeb3d760e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063fbdeb3d7906121a4908c908b908b908b908b90600401613067565b6020604051808303816000875af11580156121c3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121e79190612edc565b6040516338f3a6a160e21b81529093506001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063e3ce9a8490611c429086908c908b908790600401612ffc565b6001600160a01b038216600090815260056020908152604080832084845290915290205460ff165b92915050565b60007f000000000000000000000000000000000000000000000000000000000000000046146123405761233b604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60208201527f0000000000000000000000000000000000000000000000000000000000000000918101919091527f000000000000000000000000000000000000000000000000000000000000000060608201524660808201523060a082015260009060c00160405160208183030381529060405280519060200120905090565b905090565b507f000000000000000000000000000000000000000000000000000000000000000090565b6001600160a01b03831661238c5760405163e63f571f60e01b815260040160405180910390fd5b80516041146123b5578051604051631d9f5a5f60e01b8152610b469183916041906004016130ba565b6000816040815181106123ca576123ca612f46565b016020015160f81c90506004811080156123ec57506001600160a01b0384163b155b156123ff576123fc601b826130df565b90505b60208201516040830151600060ff84166004036124d45750604051630b135d3f60e11b80825283916001600160a01b03831690631626ba7e90612448908a908a906004016130f8565b602060405180830381865afa158015612465573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124899190613119565b7fffffffff0000000000000000000000000000000000000000000000000000000016146124cf5780868660405163694d54dd60e01b8152600401610b469392919061315b565b61258c565b8360ff1660050361252c57506001600160a01b0382166000908152600560209081526040808320888452909152902054829060ff166124cf578086866040516312cf832560e01b8152600401610b469392919061315b565b60408051600081526020810180835288905260ff861691810191909152606081018490526080810183905260019060a0016020604051602081039080840390855afa15801561257f573d6000803e3d6000fd5b5050506020604051035190505b866001600160a01b0316816001600160a01b0316146125d15760405163a806216d60e01b81526001600160a01b03808316600483015288166024820152604401610b46565b50505050505050565b6000815180845260005b81811015612600576020818501810151868301820152016125e4565b506000602082860101526020601f19601f83011685010191505092915050565b60208152600061263360208301846125da565b9392505050565b60006020828403121561264c57600080fd5b5035919050565b6001600160a01b038116811461266857600080fd5b50565b634e487b7160e01b600052604160045260246000fd5b6040805190810167ffffffffffffffff811182821017156126a4576126a461266b565b60405290565b604051601f8201601f1916810167ffffffffffffffff811182821017156126d3576126d361266b565b604052919050565b600082601f8301126126ec57600080fd5b813567ffffffffffffffff8111156127065761270661266b565b612719601f8201601f19166020016126aa565b81815284602083860101111561272e57600080fd5b816020850160208301376000918101602001919091529392505050565b60008060006060848603121561276057600080fd5b83359250602084013561277281612653565b9150604084013567ffffffffffffffff81111561278e57600080fd5b61279a868287016126db565b9150509250925092565b600067ffffffffffffffff8211156127be576127be61266b565b5060051b60200190565b600082601f8301126127d957600080fd5b813560206127ee6127e9836127a4565b6126aa565b82815260059290921b8401810191818101908684111561280d57600080fd5b8286015b84811015611c7657803561282481612653565b8352918301918301612811565b803563ffffffff8116811461284557600080fd5b919050565b600082601f83011261285b57600080fd5b8135602061286b6127e9836127a4565b82815260059290921b8401810191818101908684111561288a57600080fd5b8286015b84811015611c765761289f81612831565b835291830191830161288e565b600080600080600060a086880312156128c457600080fd5b85356128cf81612653565b945060208601359350604086013567ffffffffffffffff808211156128f357600080fd5b6128ff89838a016127c8565b9450606088013591508082111561291557600080fd5b61292189838a0161284a565b9350608088013591508082111561293757600080fd5b50612944888289016126db565b9150509295509295909350565b60008060006060848603121561296657600080fd5b833561297181612653565b925060208401359150604084013567ffffffffffffffff81111561278e57600080fd5b600080604083850312156129a757600080fd5b82356129b281612653565b946020939093013593505050565b6000602082840312156129d257600080fd5b813561263381612653565b60008060008060008060c087890312156129f657600080fd5b8635612a0181612653565b95506020870135612a1181612653565b945060408701359350606087013567ffffffffffffffff80821115612a3557600080fd5b612a418a838b016127c8565b94506080890135915080821115612a5757600080fd5b50612a6489828a0161284a565b92505060a087013590509295509295509295565b60008060008060808587031215612a8e57600080fd5b8435612a9981612653565b93506020850135612aa981612653565b93969395505050506040820135916060013590565b600082601f830112612acf57600080fd5b81356020612adf6127e9836127a4565b82815260069290921b84018101918181019086841115612afe57600080fd5b8286015b84811015611c765760408189031215612b1b5760008081fd5b612b23612681565b612b2c82612831565b8152848201356001600160601b0381168114612b485760008081fd5b81860152835291830191604001612b02565b60008060008060008060c08789031215612b7357600080fd5b8635612b7e81612653565b955060208701359450604087013567ffffffffffffffff80821115612ba257600080fd5b612bae8a838b0161284a565b95506060890135915080821115612bc457600080fd5b50612bd189828a01612abe565b935050612be060808801612831565b915060a087013590509295509295509295565b600080600060608486031215612c0857600080fd5b83359250602084013567ffffffffffffffff80821115612c2757600080fd5b612c33878388016127c8565b93506040860135915080821115612c4957600080fd5b5061279a8682870161284a565b60008060008060008060c08789031215612c6f57600080fd5b8635612c7a81612653565b95506020870135612c8a81612653565b945060408701359350606087013567ffffffffffffffff80821115612cae57600080fd5b612cba8a838b0161284a565b94506080890135915080821115612cd057600080fd5b50612cdd89828a01612abe565b925050612cec60a08801612831565b90509295509295509295565b600181811c90821680612d0c57607f821691505b60208210810361139257634e487b7160e01b600052602260045260246000fd5b60006001600160a01b0380871683528560208401528085166040840152506080606083015261152160808301846125da565b600060208284031215612d7057600080fd5b815161263381612653565b634e487b7160e01b600052601160045260246000fd5b600060018201612da357612da3612d7b565b5060010190565b600081518084526020808501945080840160005b83811015612de057815163ffffffff1687529582019590820190600101612dbe565b509495945050505050565b6001600160a01b0384168152826020820152606060408201526000612e136060830184612daa565b95945050505050565b8051801515811461284557600080fd5b600060208284031215612e3e57600080fd5b61263382612e1c565b808202811582820484141761226457612264612d7b565b600081518084526020808501945080840160005b83811015612de05781516001600160a01b031687529582019590820190600101612e72565b6001600160a01b0385168152836020820152608060408201526000612ebf6080830185612e5e565b8281036060840152612ed18185612daa565b979650505050505050565b600060208284031215612eee57600080fd5b5051919050565b60008060408385031215612f0857600080fd5b612f1183612e1c565b9150602083015190509250929050565b604081526000612f346040830185612e5e565b8281036020840152611f108185612daa565b634e487b7160e01b600052603260045260246000fd5b600081518084526020808501945080840160005b83811015612de0578151805163ffffffff1688528301516001600160601b03168388015260409096019590820190600101612f70565b6001600160a01b038716815285602082015260c060408201526000612fce60c0830187612daa565b8281036060840152612fe08187612f5c565b63ffffffff959095166080840152505060a00152949350505050565b848152600060206001600160a01b03861681840152608060408401526130256080840186612daa565b838103606085015284518082528286019183019060005b818110156130585783518352928401929184019160010161303c565b50909998505050505050505050565b6001600160a01b038616815284602082015260a06040820152600061308f60a0830186612daa565b82810360608401526130a18186612f5c565b91505063ffffffff831660808301529695505050505050565b6060815260006130cd60608301866125da565b60208301949094525060400152919050565b60ff818116838216019081111561226457612264612d7b565b82815260406020820152600061311160408301846125da565b949350505050565b60006020828403121561312b57600080fd5b81517fffffffff000000000000000000000000000000000000000000000000000000008116811461263357600080fd5b6001600160a01b0384168152826020820152606060408201526000612e1360608301846125da56fea2646970667358221220f2d50ac7cf109448ada9fff306a728e5251fe66a1c6e6ec31ba9ad713c2ad83964736f6c63430008130033", + "linkReferences": {}, + "deployedLinkReferences": {} +} \ No newline at end of file diff --git a/packages/valory/contracts/service_manager/contract.py b/packages/valory/contracts/service_manager/contract.py index 38427ba475..f3bb1a6def 100644 --- a/packages/valory/contracts/service_manager/contract.py +++ b/packages/valory/contracts/service_manager/contract.py @@ -19,7 +19,9 @@ """This module contains the class to connect to the Service Registry contract.""" +import json import logging +from pathlib import Path from typing import Any, Dict, List, Optional from aea.common import JSONLike @@ -29,7 +31,16 @@ PUBLIC_ID = PublicId.from_str("valory/service_manager:0.1.0") - +ETHEREUM_ERC20 = "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE" +ETHEREUM_IDENTIFIER = "ethereum" +SERVICE_MANAGER_TOKEN_COMPATIBLE_CHAINS = ( + 1, + 5, + 31337, + 100, + 10200, +) +SERVICE_MANAGER_BUILD = "ServiceManager.json" _logger = logging.getLogger( f"aea.packages.{PUBLIC_ID.author}.contracts.{PUBLIC_ID.name}.contract" ) @@ -41,26 +52,72 @@ class ServiceManagerContract(Contract): contract_id = PUBLIC_ID @classmethod - def get_raw_transaction( + def get_raw_transaction( # pragma: nocover cls, ledger_api: LedgerApi, contract_address: str, **kwargs: Any ) -> Optional[JSONLike]: """Get the Safe transaction.""" raise NotImplementedError @classmethod - def get_raw_message( + def get_raw_message( # pragma: nocover cls, ledger_api: LedgerApi, contract_address: str, **kwargs: Any ) -> Optional[bytes]: """Get raw message.""" raise NotImplementedError @classmethod - def get_state( + def get_state( # pragma: nocover cls, ledger_api: LedgerApi, contract_address: str, **kwargs: Any ) -> Optional[JSONLike]: """Get state.""" raise NotImplementedError + @staticmethod + def load_service_manager_abi() -> JSONLike: + """Load L2 ABI""" + path = Path(__file__).parent / "build" / SERVICE_MANAGER_BUILD + return json.loads(path.read_text(encoding="utf-8")) + + @staticmethod + def is_service_manager_token_compatible_chain(ledger_api: LedgerApi) -> bool: + """Check if we're interacting with a ServiceManagerToken compatible chain""" + return ledger_api.api.eth.chain_id in SERVICE_MANAGER_TOKEN_COMPATIBLE_CHAINS + + @classmethod + def get_instance( + cls, + ledger_api: LedgerApi, + contract_address: Optional[str] = None, + ) -> Any: + """Get contract instance.""" + if ledger_api.identifier != ETHEREUM_IDENTIFIER: + return super().get_instance( + ledger_api=ledger_api, contract_address=contract_address + ) + if cls.is_service_manager_token_compatible_chain(ledger_api=ledger_api): + contract_interface = cls.contract_interface.get(ledger_api.identifier, {}) + else: + contract_interface = cls.load_service_manager_abi() + return ledger_api.get_contract_instance(contract_interface, contract_address) + + @classmethod + def get_events( # pragma: nocover + cls, + ledger_api: LedgerApi, + contract_address: str, + event: str, + receipt: JSONLike, + ) -> Dict: + """Process receipt for events.""" + contract_interface = cls.get_instance( + ledger_api=ledger_api, + contract_address=contract_address, + ) + Event = getattr(contract_interface.events, event, None) + if Event is None: + return {"events": []} + return {"events": Event().process_receipt(receipt)} + @classmethod def get_create_transaction( # pylint: disable=too-many-arguments cls, @@ -72,28 +129,72 @@ def get_create_transaction( # pylint: disable=too-many-arguments agent_ids: List[int], agent_params: List[List[int]], threshold: int, + token: Optional[str] = None, raise_on_try: bool = False, ) -> Dict[str, Any]: """Retrieve the service owner.""" + method_args = { + "serviceOwner": owner, + "configHash": metadata_hash, + "agentIds": agent_ids, + "agentParams": agent_params, + "threshold": threshold, + } + if cls.is_service_manager_token_compatible_chain(ledger_api=ledger_api): + method_args["token"] = ledger_api.api.to_checksum_address( + token or ETHEREUM_ERC20 + ) - tx_params = ledger_api.build_transaction( + return ledger_api.build_transaction( contract_instance=cls.get_instance( ledger_api=ledger_api, contract_address=contract_address ), method_name="create", - method_args={ - "serviceOwner": owner, - "configHash": metadata_hash, - "agentIds": agent_ids, - "agentParams": agent_params, - "threshold": threshold, + method_args=method_args, + tx_args={ + "sender_address": sender, }, + raise_on_try=raise_on_try, + ) + + @classmethod + def get_update_transaction( # pylint: disable=too-many-arguments + cls, + ledger_api: LedgerApi, + contract_address: str, + sender: str, + service_id: int, + metadata_hash: str, + agent_ids: List[int], + agent_params: List[List[int]], + threshold: int, + token: Optional[str] = None, + raise_on_try: bool = False, + ) -> Dict[str, Any]: + """Retrieve the service owner.""" + method_args = { + "serviceId": service_id, + "configHash": metadata_hash, + "agentIds": agent_ids, + "agentParams": agent_params, + "threshold": threshold, + } + if cls.is_service_manager_token_compatible_chain(ledger_api=ledger_api): + method_args["token"] = ledger_api.api.to_checksum_address( + token or ETHEREUM_ERC20 + ) + + return ledger_api.build_transaction( + contract_instance=cls.get_instance( + ledger_api=ledger_api, contract_address=contract_address + ), + method_name="update", + method_args=method_args, tx_args={ "sender_address": sender, }, raise_on_try=raise_on_try, ) - return tx_params @classmethod def get_activate_registration_transaction( # pylint: disable=too-many-arguments @@ -179,3 +280,53 @@ def get_service_deploy_transaction( # pylint: disable=too-many-arguments ) return tx_params + + @classmethod + def get_terminate_service_transaction( + cls, + ledger_api: LedgerApi, + contract_address: str, + owner: str, + service_id: int, + raise_on_try: bool = False, + ) -> Dict[str, Any]: + """Retrieve the service owner.""" + + tx_params = ledger_api.build_transaction( + contract_instance=cls.get_instance( + ledger_api=ledger_api, contract_address=contract_address + ), + method_name="terminate", + method_args={ + "serviceId": service_id, + }, + tx_args={"sender_address": owner}, + raise_on_try=raise_on_try, + ) + + return tx_params + + @classmethod + def get_unbond_service_transaction( + cls, + ledger_api: LedgerApi, + contract_address: str, + owner: str, + service_id: int, + raise_on_try: bool = False, + ) -> Dict[str, Any]: + """Retrieve the service owner.""" + + tx_params = ledger_api.build_transaction( + contract_instance=cls.get_instance( + ledger_api=ledger_api, contract_address=contract_address + ), + method_name="unbond", + method_args={ + "serviceId": service_id, + }, + tx_args={"sender_address": owner}, + raise_on_try=raise_on_try, + ) + + return tx_params diff --git a/packages/valory/contracts/service_manager/contract.yaml b/packages/valory/contracts/service_manager/contract.yaml index 64795a4ec7..d7db7eb302 100644 --- a/packages/valory/contracts/service_manager/contract.yaml +++ b/packages/valory/contracts/service_manager/contract.yaml @@ -7,14 +7,14 @@ license: Apache-2.0 aea_version: '>=1.0.0, <2.0.0' fingerprint: __init__.py: bafybeiao4aiyvkvg75zfi2nf34hidx2uzcbqibc2bukyutisg5zhxskhlq - build/ServiceManager.json: bafybeiaykphmrdujhb7knvivig2qhm7ksj7sa4cppqrgbh3efq4z5yv4jm - contract.py: bafybeic2eqeygvxg45ocz3tcabam4qsulqosnkb5hi35zurght2r47aq5m + build/ServiceManager.json: bafybeiefm53534jhy5tfjgcmx4rbjrcn6tzbghw4ptggh5or6vuohdgau4 + build/ServiceManagerToken.json: bafybeidjyr2wqsiorb3u5pnfiqkzff5rgewbr5kgawev2zlah4i4f6fcom + contract.py: bafybeig4oqvm7w2oz7rdapsirjgzagwji5p5johd6klr3t6pcobmmduaza tests/__init__.py: bafybeifehip3omosjvpq3uqvxomtgrmqjoqdttyzhvu2qysybjf6btwkpi - tests/test_contract.py: bafybeifpacyxye3woxhimstciwhhqh2x357jqc3u5ex5dbyxfwoelludam + tests/test_contract.py: bafybeicqdkxo3aygm6ljjpvk6fdstelbuotxayvxwgeirqiiooclab5m34 fingerprint_ignore_patterns: [] contracts: [] class_name: ServiceManagerContract contract_interface_paths: - ethereum: build/ServiceManager.json - ethereum_hwi: build/ServiceManager.json + ethereum: build/ServiceManagerToken.json dependencies: {} diff --git a/packages/valory/contracts/service_manager/tests/test_contract.py b/packages/valory/contracts/service_manager/tests/test_contract.py index a2d50b0ac5..9efa0b750b 100644 --- a/packages/valory/contracts/service_manager/tests/test_contract.py +++ b/packages/valory/contracts/service_manager/tests/test_contract.py @@ -20,6 +20,7 @@ """Test for contract module.""" from pathlib import Path +from unittest import mock from aea_test_autonomy.base_test_classes.contracts import BaseRegistriesContractsTest from aea_test_autonomy.docker.base import skip_docker_tests @@ -84,6 +85,70 @@ def test_get_create_transaction(self) -> None: ] ) + def test_get_create_transaction_l2(self) -> None: + """Test `get_create_transaction` method.""" + + with mock.patch.object( + self.ledger_api.api, + "eth", + return_value=mock.MagicMock(chain_id=100), + ): + tx = self.contract.get_create_transaction( + ledger_api=self.ledger_api, + contract_address=self.contract_address, + owner=self.deployer_crypto.address, + sender=self.deployer_crypto.address, + metadata_hash=METADATA_HASH, + agent_ids=[AGENT_ID], + agent_params=[[NUMBER_OF_SLOTS, COST_OF_BOND]], + threshold=THRESHOLD, + ) + assert all( + [ + key + in [ + "chainId", + "nonce", + "value", + "gas", + "maxFeePerGas", + "maxPriorityFeePerGas", + "to", + "data", + ] + for key in tx.keys() + ] + ) + + def test_get_update_transaction(self) -> None: + """Test `get_update_transaction` method.""" + tx = self.contract.get_update_transaction( + ledger_api=self.ledger_api, + contract_address=self.contract_address, + sender=self.deployer_crypto.address, + service_id=2, + metadata_hash=METADATA_HASH, + agent_ids=[AGENT_ID], + agent_params=[[NUMBER_OF_SLOTS, COST_OF_BOND]], + threshold=THRESHOLD, + ) + assert all( + [ + key + in [ + "chainId", + "nonce", + "value", + "gas", + "maxFeePerGas", + "maxPriorityFeePerGas", + "to", + "data", + ] + for key in tx.keys() + ] + ) + def test_get_activate_registration_transaction(self) -> None: """Test `get_activate_registration_transaction` method""" @@ -110,3 +175,83 @@ def test_get_activate_registration_transaction(self) -> None: for key in tx.keys() ] ) + + def test_get_service_deploy_transaction(self) -> None: + """Test `get_service_deploy_transaction` method""" + + tx = self.contract.get_service_deploy_transaction( + ledger_api=self.ledger_api, + contract_address=self.contract_address, + owner=self.deployer_crypto.address, + service_id=1, + gnosis_safe_multisig="0x0E801D84Fa97b50751Dbf25036d067dCf18858bF", + deployment_payload="0x", + ) + assert all( + [ + key + in [ + "chainId", + "nonce", + "value", + "gas", + "maxFeePerGas", + "maxPriorityFeePerGas", + "to", + "data", + ] + for key in tx.keys() + ] + ) + + def test_get_terminate_service_transaction(self) -> None: + """Test `get_terminate_service_transaction` method""" + + tx = self.contract.get_terminate_service_transaction( + ledger_api=self.ledger_api, + contract_address=self.contract_address, + owner=self.deployer_crypto.address, + service_id=1, + ) + assert all( + [ + key + in [ + "chainId", + "nonce", + "value", + "gas", + "maxFeePerGas", + "maxPriorityFeePerGas", + "to", + "data", + ] + for key in tx.keys() + ] + ) + + def test_get_unbond_service_transaction(self) -> None: + """Test `get_unbond_service_transaction` method""" + + tx = self.contract.get_unbond_service_transaction( + ledger_api=self.ledger_api, + contract_address=self.contract_address, + owner=self.deployer_crypto.address, + service_id=1, + ) + assert all( + [ + key + in [ + "chainId", + "nonce", + "value", + "gas", + "maxFeePerGas", + "maxPriorityFeePerGas", + "to", + "data", + ] + for key in tx.keys() + ] + ) diff --git a/packages/valory/contracts/service_registry/build/ServiceRegistryL2.json b/packages/valory/contracts/service_registry/build/ServiceRegistryL2.json new file mode 100644 index 0000000000..0054fd27af --- /dev/null +++ b/packages/valory/contracts/service_registry/build/ServiceRegistryL2.json @@ -0,0 +1,1899 @@ +{ + "_format": "hh-sol-artifact-1", + "contractName": "ServiceRegistryL2", + "sourceName": "contracts/ServiceRegistryL2.sol", + "abi": [ + { + "inputs": [ + { + "internalType": "string", + "name": "_name", + "type": "string" + }, + { + "internalType": "string", + "name": "_symbol", + "type": "string" + }, + { + "internalType": "string", + "name": "_baseURI", + "type": "string" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "operator", + "type": "address" + } + ], + "name": "AgentInstanceRegistered", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "serviceId", + "type": "uint256" + } + ], + "name": "AgentInstancesSlotsFilled", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "agentId", + "type": "uint256" + } + ], + "name": "AgentNotFound", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "agentId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "serviceId", + "type": "uint256" + } + ], + "name": "AgentNotInService", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "componentId", + "type": "uint256" + } + ], + "name": "ComponentNotFound", + "type": "error" + }, + { + "inputs": [], + "name": "HashExists", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "sent", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "expected", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "serviceId", + "type": "uint256" + } + ], + "name": "IncorrectAgentBondingValue", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "sent", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "expected", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "serviceId", + "type": "uint256" + } + ], + "name": "IncorrectRegistrationDepositValue", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "internalType": "address", + "name": "manager", + "type": "address" + } + ], + "name": "ManagerOnly", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "provided", + "type": "address" + }, + { + "internalType": "address", + "name": "expected", + "type": "address" + }, + { + "internalType": "uint256", + "name": "serviceId", + "type": "uint256" + } + ], + "name": "OnlyOwnServiceMultisig", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "operator", + "type": "address" + }, + { + "internalType": "uint256", + "name": "serviceId", + "type": "uint256" + } + ], + "name": "OperatorHasNoInstances", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "provided", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "max", + "type": "uint256" + } + ], + "name": "Overflow", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "internalType": "address", + "name": "owner", + "type": "address" + } + ], + "name": "OwnerOnly", + "type": "error" + }, + { + "inputs": [], + "name": "Paused", + "type": "error" + }, + { + "inputs": [], + "name": "ReentrancyGuard", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "serviceId", + "type": "uint256" + } + ], + "name": "ServiceMustBeInactive", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "TransferFailed", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "multisig", + "type": "address" + } + ], + "name": "UnauthorizedMultisig", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "agentId", + "type": "uint256" + } + ], + "name": "WrongAgentId", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "numValues1", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "numValues2", + "type": "uint256" + } + ], + "name": "WrongArrayLength", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "serviceId", + "type": "uint256" + } + ], + "name": "WrongOperator", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "state", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "serviceId", + "type": "uint256" + } + ], + "name": "WrongServiceState", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "currentThreshold", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "minThreshold", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "maxThreshold", + "type": "uint256" + } + ], + "name": "WrongThreshold", + "type": "error" + }, + { + "inputs": [], + "name": "ZeroAddress", + "type": "error" + }, + { + "inputs": [], + "name": "ZeroValue", + "type": "error" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "serviceId", + "type": "uint256" + } + ], + "name": "ActivateRegistration", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "id", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "operator", + "type": "address" + }, + { + "indexed": false, + "internalType": "bool", + "name": "approved", + "type": "bool" + } + ], + "name": "ApprovalForAll", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "string", + "name": "baseURI", + "type": "string" + } + ], + "name": "BaseURIChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "serviceId", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "address", + "name": "multisig", + "type": "address" + } + ], + "name": "CreateMultisigWithAgents", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "serviceId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "bytes32", + "name": "configHash", + "type": "bytes32" + } + ], + "name": "CreateService", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "serviceId", + "type": "uint256" + } + ], + "name": "DeployService", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "Deposit", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "drainer", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "Drain", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "drainer", + "type": "address" + } + ], + "name": "DrainerUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "manager", + "type": "address" + } + ], + "name": "ManagerUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "address", + "name": "operator", + "type": "address" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "serviceId", + "type": "uint256" + } + ], + "name": "OperatorSlashed", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "operator", + "type": "address" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "serviceId", + "type": "uint256" + } + ], + "name": "OperatorUnbond", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + } + ], + "name": "OwnerUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "receiver", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "Refund", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "operator", + "type": "address" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "serviceId", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "address", + "name": "agentInstance", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "agentId", + "type": "uint256" + } + ], + "name": "RegisterInstance", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "serviceId", + "type": "uint256" + } + ], + "name": "TerminateService", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "id", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "serviceId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "bytes32", + "name": "configHash", + "type": "bytes32" + } + ], + "name": "UpdateService", + "type": "event" + }, + { + "inputs": [], + "name": "CID_PREFIX", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "VERSION", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "serviceOwner", + "type": "address" + }, + { + "internalType": "uint256", + "name": "serviceId", + "type": "uint256" + } + ], + "name": "activateRegistration", + "outputs": [ + { + "internalType": "bool", + "name": "success", + "type": "bool" + } + ], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "id", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "baseURI", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newDrainer", + "type": "address" + } + ], + "name": "changeDrainer", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newManager", + "type": "address" + } + ], + "name": "changeManager", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "multisig", + "type": "address" + }, + { + "internalType": "bool", + "name": "permission", + "type": "bool" + } + ], + "name": "changeMultisigPermission", + "outputs": [ + { + "internalType": "bool", + "name": "success", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "changeOwner", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "serviceOwner", + "type": "address" + }, + { + "internalType": "bytes32", + "name": "configHash", + "type": "bytes32" + }, + { + "internalType": "uint32[]", + "name": "agentIds", + "type": "uint32[]" + }, + { + "components": [ + { + "internalType": "uint32", + "name": "slots", + "type": "uint32" + }, + { + "internalType": "uint96", + "name": "bond", + "type": "uint96" + } + ], + "internalType": "struct AgentParams[]", + "name": "agentParams", + "type": "tuple[]" + }, + { + "internalType": "uint32", + "name": "threshold", + "type": "uint32" + } + ], + "name": "create", + "outputs": [ + { + "internalType": "uint256", + "name": "serviceId", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "serviceOwner", + "type": "address" + }, + { + "internalType": "uint256", + "name": "serviceId", + "type": "uint256" + }, + { + "internalType": "address", + "name": "multisigImplementation", + "type": "address" + }, + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + } + ], + "name": "deploy", + "outputs": [ + { + "internalType": "address", + "name": "multisig", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "drain", + "outputs": [ + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "drainer", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "unitId", + "type": "uint256" + } + ], + "name": "exists", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "serviceId", + "type": "uint256" + } + ], + "name": "getAgentInstances", + "outputs": [ + { + "internalType": "uint256", + "name": "numAgentInstances", + "type": "uint256" + }, + { + "internalType": "address[]", + "name": "agentInstances", + "type": "address[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "serviceId", + "type": "uint256" + } + ], + "name": "getAgentParams", + "outputs": [ + { + "internalType": "uint256", + "name": "numAgentIds", + "type": "uint256" + }, + { + "components": [ + { + "internalType": "uint32", + "name": "slots", + "type": "uint32" + }, + { + "internalType": "uint96", + "name": "bond", + "type": "uint96" + } + ], + "internalType": "struct AgentParams[]", + "name": "agentParams", + "type": "tuple[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "getApproved", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "serviceId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "agentId", + "type": "uint256" + } + ], + "name": "getInstancesForAgentId", + "outputs": [ + { + "internalType": "uint256", + "name": "numAgentInstances", + "type": "uint256" + }, + { + "internalType": "address[]", + "name": "agentInstances", + "type": "address[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "operator", + "type": "address" + }, + { + "internalType": "uint256", + "name": "serviceId", + "type": "uint256" + } + ], + "name": "getOperatorBalance", + "outputs": [ + { + "internalType": "uint256", + "name": "balance", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "serviceId", + "type": "uint256" + } + ], + "name": "getPreviousHashes", + "outputs": [ + { + "internalType": "uint256", + "name": "numHashes", + "type": "uint256" + }, + { + "internalType": "bytes32[]", + "name": "configHashes", + "type": "bytes32[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "serviceId", + "type": "uint256" + } + ], + "name": "getService", + "outputs": [ + { + "components": [ + { + "internalType": "uint96", + "name": "securityDeposit", + "type": "uint96" + }, + { + "internalType": "address", + "name": "multisig", + "type": "address" + }, + { + "internalType": "bytes32", + "name": "configHash", + "type": "bytes32" + }, + { + "internalType": "uint32", + "name": "threshold", + "type": "uint32" + }, + { + "internalType": "uint32", + "name": "maxNumAgentInstances", + "type": "uint32" + }, + { + "internalType": "uint32", + "name": "numAgentInstances", + "type": "uint32" + }, + { + "internalType": "enum ServiceRegistryL2.ServiceState", + "name": "state", + "type": "uint8" + }, + { + "internalType": "uint32[]", + "name": "agentIds", + "type": "uint32[]" + } + ], + "internalType": "struct ServiceRegistryL2.Service", + "name": "service", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + }, + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "isApprovedForAll", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "manager", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "mapAgentInstanceOperators", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "mapConfigHashes", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "mapMultisigs", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "mapOperatorAndServiceIdAgentInstances", + "outputs": [ + { + "internalType": "address", + "name": "instance", + "type": "address" + }, + { + "internalType": "uint32", + "name": "agentId", + "type": "uint32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "mapOperatorAndServiceIdOperatorBalances", + "outputs": [ + { + "internalType": "uint96", + "name": "", + "type": "uint96" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "mapServiceAndAgentIdAgentInstances", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "mapServiceAndAgentIdAgentParams", + "outputs": [ + { + "internalType": "uint32", + "name": "slots", + "type": "uint32" + }, + { + "internalType": "uint96", + "name": "bond", + "type": "uint96" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "mapServices", + "outputs": [ + { + "internalType": "uint96", + "name": "securityDeposit", + "type": "uint96" + }, + { + "internalType": "address", + "name": "multisig", + "type": "address" + }, + { + "internalType": "bytes32", + "name": "configHash", + "type": "bytes32" + }, + { + "internalType": "uint32", + "name": "threshold", + "type": "uint32" + }, + { + "internalType": "uint32", + "name": "maxNumAgentInstances", + "type": "uint32" + }, + { + "internalType": "uint32", + "name": "numAgentInstances", + "type": "uint32" + }, + { + "internalType": "enum ServiceRegistryL2.ServiceState", + "name": "state", + "type": "uint8" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "name", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "owner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "id", + "type": "uint256" + } + ], + "name": "ownerOf", + "outputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "operator", + "type": "address" + }, + { + "internalType": "uint256", + "name": "serviceId", + "type": "uint256" + }, + { + "internalType": "address[]", + "name": "agentInstances", + "type": "address[]" + }, + { + "internalType": "uint32[]", + "name": "agentIds", + "type": "uint32[]" + } + ], + "name": "registerAgents", + "outputs": [ + { + "internalType": "bool", + "name": "success", + "type": "bool" + } + ], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "id", + "type": "uint256" + } + ], + "name": "safeTransferFrom", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "id", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + } + ], + "name": "safeTransferFrom", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "operator", + "type": "address" + }, + { + "internalType": "bool", + "name": "approved", + "type": "bool" + } + ], + "name": "setApprovalForAll", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "string", + "name": "bURI", + "type": "string" + } + ], + "name": "setBaseURI", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address[]", + "name": "agentInstances", + "type": "address[]" + }, + { + "internalType": "uint96[]", + "name": "amounts", + "type": "uint96[]" + }, + { + "internalType": "uint256", + "name": "serviceId", + "type": "uint256" + } + ], + "name": "slash", + "outputs": [ + { + "internalType": "bool", + "name": "success", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "slashedFunds", + "outputs": [ + { + "internalType": "uint96", + "name": "", + "type": "uint96" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "interfaceId", + "type": "bytes4" + } + ], + "name": "supportsInterface", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "symbol", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "serviceOwner", + "type": "address" + }, + { + "internalType": "uint256", + "name": "serviceId", + "type": "uint256" + } + ], + "name": "terminate", + "outputs": [ + { + "internalType": "bool", + "name": "success", + "type": "bool" + }, + { + "internalType": "uint256", + "name": "refund", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "id", + "type": "uint256" + } + ], + "name": "tokenByIndex", + "outputs": [ + { + "internalType": "uint256", + "name": "unitId", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "unitId", + "type": "uint256" + } + ], + "name": "tokenURI", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "id", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "operator", + "type": "address" + }, + { + "internalType": "uint256", + "name": "serviceId", + "type": "uint256" + } + ], + "name": "unbond", + "outputs": [ + { + "internalType": "bool", + "name": "success", + "type": "bool" + }, + { + "internalType": "uint256", + "name": "refund", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "serviceOwner", + "type": "address" + }, + { + "internalType": "bytes32", + "name": "configHash", + "type": "bytes32" + }, + { + "internalType": "uint32[]", + "name": "agentIds", + "type": "uint32[]" + }, + { + "components": [ + { + "internalType": "uint32", + "name": "slots", + "type": "uint32" + }, + { + "internalType": "uint96", + "name": "bond", + "type": "uint96" + } + ], + "internalType": "struct AgentParams[]", + "name": "agentParams", + "type": "tuple[]" + }, + { + "internalType": "uint32", + "name": "threshold", + "type": "uint32" + }, + { + "internalType": "uint256", + "name": "serviceId", + "type": "uint256" + } + ], + "name": "update", + "outputs": [ + { + "internalType": "bool", + "name": "success", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + } + ], + "bytecode": "0x60806040526001600a553480156200001657600080fd5b5060405162005bcb38038062005bcb83398101604081905262000039916200014d565b828260006200004983826200026d565b5060016200005882826200026d565b50600891506200006b905082826200026d565b5050600680546001600160a01b0319163317905550620003399050565b634e487b7160e01b600052604160045260246000fd5b600082601f830112620000b057600080fd5b81516001600160401b0380821115620000cd57620000cd62000088565b604051601f8301601f19908116603f01168101908282118183101715620000f857620000f862000088565b816040528381526020925086838588010111156200011557600080fd5b600091505b838210156200013957858201830151818301840152908201906200011a565b600093810190920192909252949350505050565b6000806000606084860312156200016357600080fd5b83516001600160401b03808211156200017b57600080fd5b62000189878388016200009e565b94506020860151915080821115620001a057600080fd5b620001ae878388016200009e565b93506040860151915080821115620001c557600080fd5b50620001d4868287016200009e565b9150509250925092565b600181811c90821680620001f357607f821691505b6020821081036200021457634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156200026857600081815260208120601f850160051c81016020861015620002435750805b601f850160051c820191505b8181101562000264578281556001016200024f565b5050505b505050565b81516001600160401b0381111562000289576200028962000088565b620002a1816200029a8454620001de565b846200021a565b602080601f831160018114620002d95760008415620002c05750858301515b600019600386901b1c1916600185901b17855562000264565b600085815260208120601f198616915b828110156200030a57888601518255948401946001909101908401620002e9565b5085821015620003295787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b61588280620003496000396000f3fe6080604052600436106103345760003560e01c806370a08231116101b0578063a60e4c3c116100ec578063dff7672411610095578063ef0e239b1161006f578063ef0e239b14610af7578063f908bc7714610b24578063fbdeb3d714610b44578063ffa1ad7414610b6457600080fd5b8063dff7672414610a96578063e23f6fb414610aa9578063e985e9c514610abc57600080fd5b8063c87b56dd116100c6578063c87b56dd14610a36578063cbf994f814610a56578063ccc9305d14610a7657600080fd5b8063a60e4c3c146109c8578063a6f9dae1146109f6578063b88d4fde14610a1657600080fd5b80638a2bd86f116101595780639890220b116101335780639890220b1461093c578063a22cb46514610951578063a3fbbaae14610971578063a5d059ca1461099157600080fd5b80638a2bd86f146108c25780638da5cb5b1461090757806395d89b411461092757600080fd5b80637c5e63e01161018a5780637c5e63e01461084d57806382694b1d1461088257806386a2bdd4146108a257600080fd5b806370a08231146107c9578063718934d8146107e957806373b8b6a21461082d57600080fd5b806342842e0e1161027f57806355f804b3116102285780636352211e116102025780636352211e1461070a57806363dd76151461072a5780636c0360eb146107945780636f99f15c146107a957600080fd5b806355f804b3146106a357806357838e85146106c35780635e4507fa146106ea57600080fd5b80634eb780da116102595780634eb780da1461062d5780634f558e79146106635780634f6ccce71461068357600080fd5b806342842e0e146105cd578063481c6a75146105ed5780634d486f851461060d57600080fd5b806318160ddd116102e157806323b872dd116102bb57806323b872dd146104d057806342144854146104f05780634236aff81461053e57600080fd5b806318160ddd146104505780631de286ba1461047457806321e4f7bb146104a257600080fd5b8063095ea7b311610312578063095ea7b3146103de57806310c6aa191461040057806317351f7e1461042057600080fd5b806301ffc9a71461033957806306fdde031461036e578063081812fc14610390575b600080fd5b34801561034557600080fd5b506103596103543660046149a2565b610b95565b60405190151581526020015b60405180910390f35b34801561037a57600080fd5b50610383610be7565b6040516103659190614a16565b34801561039c57600080fd5b506103c66103ab366004614a29565b6004602052600090815260409020546001600160a01b031681565b6040516001600160a01b039091168152602001610365565b3480156103ea57600080fd5b506103fe6103f9366004614a57565b610c75565b005b34801561040c57600080fd5b506103fe61041b366004614a83565b610d5c565b34801561042c57600080fd5b5061035961043b366004614a83565b60126020526000908152604090205460ff1681565b34801561045c57600080fd5b5061046660095481565b604051908152602001610365565b34801561048057600080fd5b5061049461048f366004614a29565b610e15565b604051610365929190614aa0565b3480156104ae57600080fd5b506104c26104bd366004614b07565b61106b565b604051610365929190614b6d565b3480156104dc57600080fd5b506103fe6104eb366004614b8e565b611159565b3480156104fc57600080fd5b5061052661050b366004614a29565b6010602052600090815260409020546001600160601b031681565b6040516001600160601b039091168152602001610365565b34801561054a57600080fd5b506105ba610559366004614a29565b6013602052600090815260409020805460018201546002909201546001600160601b03821692600160601b928390046001600160a01b031692909163ffffffff808216926401000000008304821692600160401b8104909216910460ff1687565b6040516103659796959493929190614c07565b3480156105d957600080fd5b506103fe6105e8366004614b8e565b611333565b3480156105f957600080fd5b506007546103c6906001600160a01b031681565b34801561061957600080fd5b506104c2610628366004614a29565b611428565b34801561063957600080fd5b506103c6610648366004614a83565b6011602052600090815260409020546001600160a01b031681565b34801561066f57600080fd5b5061035961067e366004614a29565b61157a565b34801561068f57600080fd5b5061046661069e366004614a29565b61159c565b3480156106af57600080fd5b506103fe6106be366004614d2a565b6115e1565b3480156106cf57600080fd5b50600b546103c690600160601b90046001600160a01b031681565b3480156106f657600080fd5b506103c6610705366004614b07565b61168a565b34801561071657600080fd5b506103c6610725366004614a29565b6116c2565b34801561073657600080fd5b50610770610745366004614a29565b600e6020526000908152604090205463ffffffff81169064010000000090046001600160601b031682565b6040805163ffffffff90931683526001600160601b03909116602083015201610365565b3480156107a057600080fd5b50610383611727565b3480156107b557600080fd5b50600b54610526906001600160601b031681565b3480156107d557600080fd5b506104666107e4366004614a83565b611734565b3480156107f557600080fd5b50610809610804366004614b07565b6117a8565b604080516001600160a01b03909316835263ffffffff909116602083015201610365565b34801561083957600080fd5b50610359610848366004614e22565b6117ee565b34801561085957600080fd5b506103836040518060400160405280600981526020016806630313730313232360bc1b81525081565b34801561088e57600080fd5b5061035961089d366004614eec565b611c43565b3480156108ae57600080fd5b506104666108bd366004614b07565b611cdc565b3480156108ce57600080fd5b506104666108dd366004614a57565b60a01b6001600160a01b03909116176000908152601060205260409020546001600160601b031690565b34801561091357600080fd5b506006546103c6906001600160a01b031681565b34801561093357600080fd5b50610383611d0d565b34801561094857600080fd5b50610466611d1a565b34801561095d57600080fd5b506103fe61096c366004614eec565b611e78565b34801561097d57600080fd5b506103fe61098c366004614a83565b611ee4565b34801561099d57600080fd5b506109b16109ac366004614a57565b611f95565b604080519215158352602083019190915201610365565b3480156109d457600080fd5b506109e86109e3366004614a29565b612431565b604051610365929190614f2a565b348015610a0257600080fd5b506103fe610a11366004614a83565b612495565b348015610a2257600080fd5b506103fe610a31366004614f78565b612546565b348015610a4257600080fd5b50610383610a51366004614a29565b61262b565b348015610a6257600080fd5b50610359610a7136600461511a565b6126a5565b348015610a8257600080fd5b506109b1610a91366004614a57565b612c33565b610359610aa43660046151b3565b612f95565b610359610ab7366004614a57565b613590565b348015610ac857600080fd5b50610359610ad7366004615233565b600560209081526000928352604080842090915290825290205460ff1681565b348015610b0357600080fd5b50610b17610b12366004614a29565b61370f565b6040516103659190615297565b348015610b3057600080fd5b506103c6610b3f366004615333565b61388f565b348015610b5057600080fd5b50610466610b5f3660046153a7565b613c60565b348015610b7057600080fd5b50610383604051806040016040528060058152602001640312e302e360dc1b81525081565b60006301ffc9a760e01b6001600160e01b031983161480610bc657506380ac58cd60e01b6001600160e01b03198316145b80610be15750635b5e139f60e01b6001600160e01b03198316145b92915050565b60008054610bf490615438565b80601f0160208091040260200160405190810160405280929190818152602001828054610c2090615438565b8015610c6d5780601f10610c4257610100808354040283529160200191610c6d565b820191906000526020600020905b815481529060010190602001808311610c5057829003601f168201915b505050505081565b6000818152600260205260409020546001600160a01b031633811480610cbe57506001600160a01b038116600090815260056020908152604080832033845290915290205460ff165b610d005760405162461bcd60e51b815260206004820152600e60248201526d1393d517d055551213d49256915160921b60448201526064015b60405180910390fd5b60008281526004602052604080822080546001600160a01b0319166001600160a01b0387811691821790925591518593918516917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591a4505050565b6006546001600160a01b03163314610d9c5760065460405163521eb56d60e11b81523360048201526001600160a01b039091166024820152604401610cf7565b6001600160a01b038116610dc35760405163d92e233d60e01b815260040160405180910390fd5b600b80546001600160601b0316600160601b6001600160a01b038416908102919091179091556040517f8d1e8547016120917daad7f81c42b48f7fee379badc48f1889f0f43bb619472590600090a250565b600081815260136020908152604080832081516101008101835281546001600160601b03811682526001600160a01b03600160601b918290041694820194909452600182015492810192909252600281015463ffffffff808216606085810191909152640100000000830482166080860152600160401b830490911660a0850152938593929160c084019160ff9104166005811115610eb657610eb6614bcf565b6005811115610ec757610ec7614bcf565b815260200160038201805480602002602001604051908101604052809291908181526020018280548015610f4657602002820191906000526020600020906000905b82829054906101000a900463ffffffff1663ffffffff1681526020019060040190602082600301049283019260010382029150808411610f095790505b50505050508152505090508060e001515192508267ffffffffffffffff811115610f7257610f72614c62565b604051908082528060200260200182016040528015610fb757816020015b6040805180820190915260008082526020820152815260200190600190039081610f905790505b50915060005b8381101561106457600085905060208360e001518381518110610fe257610fe2615472565b60209081029190910181015163ffffffff90811690921b929092176000818152600e845260409081902081518083019092525492831681526401000000009092046001600160601b031692820192909252845185908490811061104757611047615472565b6020026020010181905250508061105d9061549e565b9050610fbd565b5050915091565b602081811b83176000818152600f909252604090912054906060908267ffffffffffffffff81111561109f5761109f614c62565b6040519080825280602002602001820160405280156110c8578160200160208202803683370190505b50915060005b83811015611150576000828152600f602052604090208054829081106110f6576110f6615472565b9060005260206000200160009054906101000a90046001600160a01b031683828151811061112657611126615472565b6001600160a01b0390921660209283029190910190910152806111488161549e565b9150506110ce565b50509250929050565b6000818152600260205260409020546001600160a01b038481169116146111c25760405162461bcd60e51b815260206004820152600a60248201527f57524f4e475f46524f4d000000000000000000000000000000000000000000006044820152606401610cf7565b6001600160a01b03821661120c5760405162461bcd60e51b81526020600482015260116024820152701253959053125117d49150d25412515395607a1b6044820152606401610cf7565b336001600160a01b038416148061124657506001600160a01b038316600090815260056020908152604080832033845290915290205460ff165b8061126757506000818152600460205260409020546001600160a01b031633145b6112a45760405162461bcd60e51b815260206004820152600e60248201526d1393d517d055551213d49256915160921b6044820152606401610cf7565b6001600160a01b0380841660008181526003602090815260408083208054600019019055938616808352848320805460010190558583526002825284832080546001600160a01b03199081168317909155600490925284832080549092169091559251849392917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91a4505050565b61133e838383611159565b6001600160a01b0382163b1561142357604051630a85bd0160e11b8082523360048301526001600160a01b03858116602484015260448301849052608060648401526000608484015290919084169063150b7a029060a4016020604051808303816000875af11580156113b5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113d991906154b7565b6001600160e01b031916146114235760405162461bcd60e51b815260206004820152601060248201526f155394d0519157d49150d2541251539560821b6044820152606401610cf7565b505050565b600081815260136020908152604080832081516101008101835281546001600160601b03811682526001600160a01b03600160601b918290041694820194909452600182015492810192909252600281015463ffffffff808216606085810191909152640100000000830482166080860152600160401b830490911660a0850152938593929160c084019160ff91041660058111156114c9576114c9614bcf565b60058111156114da576114da614bcf565b81526020016003820180548060200260200160405190810160405280929190818152602001828054801561155957602002820191906000526020600020906000905b82829054906101000a900463ffffffff1663ffffffff168152602001906004019060208260030104928301926001038202915080841161151c5790505b505050505081525050905061156e8185613f67565b91508151925050915091565b60008082118015610be157506009546115949060016154d4565b821092915050565b60006115a98260016154d4565b90506009548111156115dc57600954604051637ae5968560e01b8152610cf7918391600401918252602082015260400190565b919050565b6006546001600160a01b031633146116215760065460405163521eb56d60e11b81523360048201526001600160a01b039091166024820152604401610cf7565b805160000361164357604051637c946ed760e01b815260040160405180910390fd5b600861164f8282615535565b507f5411e8ebf1636d9e83d5fc4900bf80cbac82e8790da2a4c94db4895e889eedf68160405161167f9190614a16565b60405180910390a150565b600f60205281600052604060002081815481106116a657600080fd5b6000918252602090912001546001600160a01b03169150829050565b6000818152600260205260409020546001600160a01b0316806115dc5760405162461bcd60e51b815260206004820152600a60248201527f4e4f545f4d494e544544000000000000000000000000000000000000000000006044820152606401610cf7565b60088054610bf490615438565b60006001600160a01b03821661178c5760405162461bcd60e51b815260206004820152600c60248201527f5a45524f5f4144445245535300000000000000000000000000000000000000006044820152606401610cf7565b506001600160a01b031660009081526003602052604090205490565b600d60205281600052604060002081815481106117c457600080fd5b6000918252602090912001546001600160a01b0381169250600160a01b900463ffffffff16905082565b600081815260136020908152604080832081516101008101835281546001600160601b0381168252600160601b908190046001600160a01b031694820194909452600182015492810192909252600281015463ffffffff8082166060850152640100000000820481166080850152600160401b82041660a0840152849360c08401910460ff16600581111561188557611885614bcf565b600581111561189657611896614bcf565b81526020016003820180548060200260200160405190810160405280929190818152602001828054801561191557602002820191906000526020600020906000905b82829054906101000a900463ffffffff1663ffffffff16815260200190600401906020826003010492830192600103820291508084116118d85790505b50505050508152505090506004600581111561193357611933614bcf565b8160c00151600581111561194957611949614bcf565b14611988578060c00151600581111561196457611964614bcf565b604051633c053f9d60e21b8152600481019190915260248101849052604401610cf7565b83518551146119b757845184516040516308151c1160e41b815260048101929092526024820152604401610cf7565b80602001516001600160a01b0316336001600160a01b031614611a0b5760208101516040516379f91cd360e01b81523360048201526001600160a01b03909116602482015260448101849052606401610cf7565b845160005b81811015611c3657600060116000898481518110611a3057611a30615472565b6020908102919091018101516001600160a01b03908116835282820193909352604091820160009081205490931660a08a901b81178085526010909252919092205489519193506001600160601b03169081908a9086908110611a9557611a95615472565b60200260200101516001611aa991906155f5565b6001600160601b03161115611b0357600b8054829190600090611ad69084906001600160601b03166155f5565b92506101000a8154816001600160601b0302191690836001600160601b0316021790555060009050611b87565b888481518110611b1557611b15615472565b6020908102919091010151600b8054600090611b3b9084906001600160601b03166155f5565b92506101000a8154816001600160601b0302191690836001600160601b03160217905550888481518110611b7157611b71615472565b602002602001015181611b84919061561c565b90505b600082815260106020526040902080546bffffffffffffffffffffffff19166001600160601b038316179055885188906001600160a01b038516907fa2e524bd0f71903485fbb3d6d50cb305f61005ceea2047c3ac92aa7e0d104306908c9088908110611bf657611bf6615472565b6020026020010151604051611c1a91906001600160601b0391909116815260200190565b60405180910390a350505080611c2f9061549e565b9050611a10565b5060019695505050505050565b6006546000906001600160a01b03163314611c865760065460405163521eb56d60e11b81523360048201526001600160a01b039091166024820152604401610cf7565b6001600160a01b038316611cad5760405163d92e233d60e01b815260040160405180910390fd5b506001600160a01b03919091166000908152601260205260409020805460ff1916911515919091179055600190565b600c6020528160005260406000208181548110611cf857600080fd5b90600052602060002001600091509150505481565b60018054610bf490615438565b60006001600a541115611d40576040516345f5ce8b60e11b815260040160405180910390fd5b6002600a55600b54600160601b90046001600160a01b03163314611d9257600b5460405163312d21ff60e11b8152336004820152600160601b9091046001600160a01b03166024820152604401610cf7565b50600b546001600160601b03168015611e7057600b80546bffffffffffffffffffffffff19169055604051600090339083908381818185875af1925050503d8060008114611dfc576040519150601f19603f3d011682016040523d82523d6000602084013e611e01565b606091505b5050905080611e395760405163cd3f165960e01b81526000600482015230602482015233604482015260648101839052608401610cf7565b60405182815233907ff36f4d6622e16a536bbb049064af779cdd483a0b388d347d3752a65f1058bf5b9060200160405180910390a2505b6001600a5590565b3360008181526005602090815260408083206001600160a01b03871680855290835292819020805460ff191686151590811790915590519081529192917f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a35050565b6006546001600160a01b03163314611f245760065460405163521eb56d60e11b81523360048201526001600160a01b039091166024820152604401610cf7565b6001600160a01b038116611f4b5760405163d92e233d60e01b815260040160405180910390fd5b600780546001600160a01b0319166001600160a01b0383169081179091556040517f2c1c11af44aa5608f1dca38c00275c30ea091e02417d36e70e9a1538689c433d90600090a250565b6000806001600a541115611fbc576040516345f5ce8b60e11b815260040160405180910390fd5b6002600a556007546001600160a01b031633146120015760075460405163312d21ff60e11b81523360048201526001600160a01b039091166024820152604401610cf7565b6001600160a01b0384166120285760405163d92e233d60e01b815260040160405180910390fd5b600083815260136020526040902060056002820154600160601b900460ff16600581111561205857612058614bcf565b146120a1576002810154600160601b900460ff16600581111561207d5761207d614bcf565b604051633c053f9d60e21b8152600481019190915260248101859052604401610cf7565b60a084901b6001600160a01b038616176000818152600d6020908152604080832080548251818502810185019093528083529192909190849084015b8282101561212957600084815260209081902060408051808201909152908401546001600160a01b0381168252600160a01b900463ffffffff16818301528252600190920191016120dd565b50508251929350505060008190036121665760405163df2ddd7360e01b81526001600160a01b038916600482015260248101889052604401610cf7565b808460020160088282829054906101000a900463ffffffff16612189919061563c565b92506101000a81548163ffffffff021916908363ffffffff1602179055508360020160089054906101000a900463ffffffff1663ffffffff166000036121df5760028401805460ff60601b1916600160601b1790555b60005b818110156122a7576000889050602084838151811061220357612203615472565b60209081029190910181015181015163ffffffff1690911b919091176000818152600e90925260409091205461224a9064010000000090046001600160601b0316886154d4565b96506011600085848151811061226257612262615472565b602090810291909101810151516001600160a01b0316825281019190915260400160002080546001600160a01b0319169055508061229f8161549e565b9150506121e2565b506000838152600d602052604081206122bf91614859565b6000838152601060205260409020546001600160601b0316808611156122ec57806001600160601b031695505b85156123e55760008481526010602052604080822080546bffffffffffffffffffffffff19169055516001600160a01b038b169088908381818185875af1925050503d806000811461235a576040519150601f19603f3d011682016040523d82523d6000602084013e61235f565b606091505b50509050806123a05760405163cd3f165960e01b8152600060048201523060248201526001600160a01b038b16604482015260648101889052608401610cf7565b896001600160a01b03167fbb28353e4598c3b9199101a66e0989549b659a59a54d2c27fbb183f1932c8e6d886040516123db91815260200190565b60405180910390a2505b60405188906001600160a01b038b16907f5ebf7fe30be09f0f03b9195632508d95c8b67bf010c93abda67f70d5d9599d1e90600090a350506001600a8190559793965092945050505050565b6000818152600c60209081526040808320805482518185028101850190935280835260609383018282801561248557602002820191906000526020600020905b815481526020019060010190808311612471575b5050505050905080519150915091565b6006546001600160a01b031633146124d55760065460405163521eb56d60e11b81523360048201526001600160a01b039091166024820152604401610cf7565b6001600160a01b0381166124fc5760405163d92e233d60e01b815260040160405180910390fd5b600680546001600160a01b0319166001600160a01b0383169081179091556040517f4ffd725fc4a22075e9ec71c59edf9c38cdeb588a91b24fc5b61388c5be41282b90600090a250565b612551858585611159565b6001600160a01b0384163b1561262457604051630a85bd0160e11b808252906001600160a01b0386169063150b7a02906125979033908a90899089908990600401615659565b6020604051808303816000875af11580156125b6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125da91906154b7565b6001600160e01b031916146126245760405162461bcd60e51b815260206004820152601060248201526f155394d0519157d49150d2541251539560821b6044820152606401610cf7565b5050505050565b6000818152601360205260408120600101546060915060086040518060400160405280600981526020016806630313730313232360bc1b81525061266e836140b8565b61267b608085901b6140b8565b60405160200161268e94939291906156ad565b604051602081830303815290604052915050919050565b6007546000906001600160a01b031633146126e85760075460405163312d21ff60e11b81523360048201526001600160a01b039091166024820152604401610cf7565b60006126f3836116c2565b9050876001600160a01b0316816001600160a01b03161461273a5760405163521eb56d60e11b81526001600160a01b03808a16600483015282166024820152604401610cf7565b600083815260136020908152604080832081516101008101835281546001600160601b03811682526001600160a01b03600160601b918290041694820194909452600182015492810192909252600281015463ffffffff8082166060850152640100000000820481166080850152600160401b82041660a08401529192909160c084019160ff91041660058111156127d4576127d4614bcf565b60058111156127e5576127e5614bcf565b81526020016003820180548060200260200160405190810160405280929190818152602001828054801561286457602002820191906000526020600020906000905b82829054906101000a900463ffffffff1663ffffffff16815260200190600401906020826003010492830192600103820291508084116128275790505b50505050508152505090506001600581111561288257612882614bcf565b8160c00151600581111561289857612898614bcf565b146128b3578060c00151600581111561207d5761207d614bcf565b6128be888888614288565b63ffffffff85166060820152600060808201819052875167ffffffffffffffff8111156128ed576128ed614c62565b604051908082528060200260200182016040528015612916578160200160208202803683370190505b5090506000885167ffffffffffffffff81111561293557612935614c62565b60405190808252806020026020018201604052801561297a57816020015b60408051808201909152600080825260208201528152602001906001900390816129535790505b5090506000805b8a51811015612aaf5789818151811061299c5761299c615472565b60200260200101516000015163ffffffff16600003612a1157600088905060208c83815181106129ce576129ce615472565b60209081029190910181015163ffffffff1690911b919091176000908152600e9091526040902080546fffffffffffffffffffffffffffffffff19169055612a9d565b8a8181518110612a2357612a23615472565b6020026020010151848381518110612a3d57612a3d615472565b602002602001019063ffffffff16908163ffffffff1681525050898181518110612a6957612a69615472565b6020026020010151838381518110612a8357612a83615472565b60200260200101819052508180612a999061549e565b9250505b80612aa78161549e565b915050612981565b5060408401518b8114612ae6576000888152600c602090815260408083208054600181018255908452919092200182905585018c90525b612af3858585858c614398565b6000888152601360209081526040918290208751918801516001600160a01b0316600160601b9081026001600160601b03909316929092178155918701516001830155606087015160028301805460808a015160a08b015163ffffffff908116600160401b026bffffffff0000000000000000199282166401000000000267ffffffffffffffff199094169190951617919091179081168317825560c08a01518a9594909360ff60601b19166cffffffffff0000000000000000199092169190911790836005811115612bc857612bc8614bcf565b021790555060e08201518051612be891600384019160209091019061487a565b50506040518d81528991507fff312ce131c4d73ac90ece91266be7090486c5e15f78b7ea2b108c36dfd475299060200160405180910390a25060019c9b505050505050505050505050565b6000806001600a541115612c5a576040516345f5ce8b60e11b815260040160405180910390fd5b6002600a556007546001600160a01b03163314612c9f5760075460405163312d21ff60e11b81523360048201526001600160a01b039091166024820152604401610cf7565b6000612caa846116c2565b9050846001600160a01b0316816001600160a01b031614612cf15760405163521eb56d60e11b81526001600160a01b03808716600483015282166024820152604401610cf7565b600084815260136020526040902060016002820154600160601b900460ff166005811115612d2157612d21614bcf565b1480612d4c575060056002820154600160601b900460ff166005811115612d4a57612d4a614bcf565b145b15612d95576002810154600160601b900460ff166005811115612d7157612d71614bcf565b604051633c053f9d60e21b8152600481019190915260248101869052604401610cf7565b6002810154600160401b900463ffffffff1615612dcf5760028101805460ff60601b19166c05000000000000000000000000179055612de5565b60028101805460ff60601b1916600160601b1790555b60005b6003820154811015612e725760008690506020836003018381548110612e1057612e10615472565b90600052602060002090600891828204019190066004029054906101000a900463ffffffff1663ffffffff16901b81179050600f60008281526020019081526020016000206000612e619190614929565b50612e6b8161549e565b9050612de8565b5080546040516001600160601b0390911693506000906001600160a01b0388169085908381818185875af1925050503d8060008114612ecd576040519150601f19603f3d011682016040523d82523d6000602084013e612ed2565b606091505b5050905080612f135760405163cd3f165960e01b8152600060048201523060248201526001600160a01b038816604482015260648101859052608401610cf7565b866001600160a01b03167fbb28353e4598c3b9199101a66e0989549b659a59a54d2c27fbb183f1932c8e6d85604051612f4e91815260200190565b60405180910390a260405186907fe45f5b9540df4f71b7e044809fa318806328c1ea2388a70c7373d97ccf8a0faa90600090a250506001600a819055959194509092505050565b6007546000906001600160a01b03163314612fd85760075460405163312d21ff60e11b81523360048201526001600160a01b039091166024820152604401610cf7565b815183511461300757825182516040516308151c1160e41b815260048101929092526024820152604401610cf7565b6000848152601360205260409020600280820154600160601b900460ff16600581111561303657613036614bcf565b1461305b576002810154600160601b900460ff166005811115612d7157612d71614bcf565b83516000805b82811015613150576000889050602087838151811061308257613082615472565b60209081029190910181015163ffffffff90811690921b929092176000818152600e845260408082208151808301909252549384168082526401000000009094046001600160601b0316948101949094529092919003613123578783815181106130ee576130ee615472565b60200260200101518a6040516332832be560e21b8152600401610cf792919063ffffffff929092168252602082015260400190565b602081015161313b906001600160601b0316856154d4565b93505050806131499061549e565b9050613061565b5080341461318157604051637ebbcab960e11b81523460048201526024810182905260448101889052606401610cf7565b6001600160a01b0388811660009081526011602052604090205416156131bd576040516322ddebd960e21b815260048101889052602401610cf7565b60a087901b6001600160a01b0389161760005b838110156134b15760008882815181106131ec576131ec615472565b60200260200101519050600088838151811061320a5761320a615472565b60200260200101519050816001600160a01b03168c6001600160a01b031603613249576040516322ddebd960e21b8152600481018c9052602401610cf7565b6001600160a01b0382811660009081526011602052604090205416156132a0576001600160a01b038281166000908152601160205260409081902054905163631695bd60e01b815291166004820152602401610cf7565b60008b905060208a85815181106132b9576132b9615472565b60209081029190910181015163ffffffff90811690921b929092176000818152600e8452604080822054600f90955290205490929091169003613312576040516304ad100760e21b8152600481018d9052602401610cf7565b6000818152600f602090815260408083208054600181810183559185528385200180546001600160a01b03808a166001600160a01b031990921682179092558a8652600d8552838620845180860190955290845263ffffffff8089168587019081528254948501835591875294909520925192909101805494518416600160a01b0277ffffffffffffffffffffffffffffffffffffffffffffffff19909516929091169190911792909217909155600289018054600160401b90049091169060086133dc8361573f565b91906101000a81548163ffffffff021916908363ffffffff160217905550508c60116000856001600160a01b03166001600160a01b0316815260200190815260200160002060006101000a8154816001600160a01b0302191690836001600160a01b03160217905550826001600160a01b03168c8e6001600160a01b03167f6835389a6da5341647f18cbe0a89c56f473f4c17bfaee6e6d07d61f1928e0b7c85604051613495919063ffffffff91909116815260200190565b60405180910390a4505050806134aa9061549e565b90506131d0565b50600284015463ffffffff64010000000082048116600160401b90920416036134f35760028401805460ff60601b19166c030000000000000000000000001790555b6000818152601060205260408120805434929061351a9084906001600160601b03166155f5565b92506101000a8154816001600160601b0302191690836001600160601b03160217905550886001600160a01b03167fe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c3460405161357991815260200190565b60405180910390a250600198975050505050505050565b6007546000906001600160a01b031633146135d35760075460405163312d21ff60e11b81523360048201526001600160a01b039091166024820152604401610cf7565b60006135de836116c2565b9050836001600160a01b0316816001600160a01b0316146136255760405163521eb56d60e11b81526001600160a01b03808616600483015282166024820152604401610cf7565b600083815260136020526040902060016002820154600160601b900460ff16600581111561365557613655614bcf565b1461367657604051635960d22f60e11b815260048101859052602401610cf7565b80546001600160601b031634146136bb578054604051631c30abbb60e31b81523460048201526001600160601b03909116602482015260448101859052606401610cf7565b60028101805460ff60601b19166c0200000000000000000000000017905560405184907fa48b531f972c0e4aca57afcc5c099c52a7bd21bc5e2a1b733eec3be9e88da97a90600090a2506001949350505050565b6137576040805161010081018252600080825260208201819052918101829052606081018290526080810182905260a081018290529060c08201908152602001606081525090565b60008281526013602090815260409182902082516101008101845281546001600160601b0381168252600160601b908190046001600160a01b031693820193909352600182015493810193909352600281015463ffffffff8082166060860152640100000000820481166080860152600160401b82041660a0850152909160c08401910460ff1660058111156137ef576137ef614bcf565b600581111561380057613800614bcf565b81526020016003820180548060200260200160405190810160405280929190818152602001828054801561387f57602002820191906000526020600020906000905b82829054906101000a900463ffffffff1663ffffffff16815260200190600401906020826003010492830192600103820291508084116138425790505b5050505050815250509050919050565b60006001600a5411156138b5576040516345f5ce8b60e11b815260040160405180910390fd5b6002600a556007546001600160a01b031633146138fa5760075460405163312d21ff60e11b81523360048201526001600160a01b039091166024820152604401610cf7565b6000613905856116c2565b9050856001600160a01b0316816001600160a01b03161461394c5760405163521eb56d60e11b81526001600160a01b03808816600483015282166024820152604401610cf7565b6001600160a01b03841660009081526012602052604090205460ff1661398f5760405162a2307960e51b81526001600160a01b0385166004820152602401610cf7565b600085815260136020526040902060036002820154600160601b900460ff1660058111156139bf576139bf614bcf565b14613a08576002810154600160601b900460ff1660058111156139e4576139e4614bcf565b604051633c053f9d60e21b8152600481019190915260248101879052604401610cf7565b604080516101008101825282546001600160601b0381168252600160601b908190046001600160a01b03166020830152600184015492820192909252600283015463ffffffff8082166060840152640100000000820481166080840152600160401b82041660a0830152600092613b359291859160c08401910460ff166005811115613a9657613a96614bcf565b6005811115613aa757613aa7614bcf565b815260200160038201805480602002602001604051908101604052809291908181526020018280548015613b2657602002820191906000526020600020906000905b82829054906101000a900463ffffffff1663ffffffff1681526020019060040190602082600301049283019260010382029150808411613ae95790505b50505050508152505088613f67565b6002830154604051631e731b7560e31b81529192506001600160a01b0388169163f398dba891613b7291859163ffffffff16908a90600401615762565b6020604051808303816000875af1158015613b91573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613bb5919061579d565b82546001600160601b0316600160601b6001600160a01b03831690810291909117845560028401805460ff60601b19166c040000000000000000000000001790556040519195509088907f2d53f895cd5faf3cddba94a25c2ced2105885b5b37450ff430ffa3cbdf332c7490600090a360405187907fa133ed72c03a7d008deaae618a61613c4fd41c67bba1cad1a6bc0a1c5a9c156e90600090a250506001600a5550949350505050565b60006001600a541115613c86576040516345f5ce8b60e11b815260040160405180910390fd5b6002600a556007546001600160a01b03163314613ccb5760075460405163312d21ff60e11b81523360048201526001600160a01b039091166024820152604401610cf7565b6001600160a01b038616613cf25760405163d92e233d60e01b815260040160405180910390fd5b613cfd858585614288565b60005b8451811015613d9157838181518110613d1b57613d1b615472565b60200260200101516000015163ffffffff1660001480613d615750838181518110613d4857613d48615472565b6020026020010151602001516001600160601b03166000145b15613d7f57604051637c946ed760e01b815260040160405180910390fd5b80613d898161549e565b915050613d00565b505060095480613da08161549e565b915050613deb6040805161010081018252600080825260208201819052918101829052606081018290526080810182905260a081018290529060c08201908152602001606081525090565b63ffffffff8316606082015260408101869052600160c082018181525050613e17818686885186614398565b6000828152601360209081526040918290208351918401516001600160a01b0316600160601b9081026001600160601b039093169290921781559183015160018301556060830151600283018054608086015160a087015163ffffffff908116600160401b026bffffffff0000000000000000199282166401000000000267ffffffffffffffff199094169190951617919091179081168317825560c0860151869594909360ff60601b19166cffffffffff0000000000000000199092169190911790836005811115613eec57613eec614bcf565b021790555060e08201518051613f0c91600384019160209091019061487a565b5050506009829055613f1e878361464f565b817fb34c1e02384201736eb4693b9b173306cb41bff12f15894dea5773088e9a3b1c87604051613f5091815260200190565b60405180910390a2506001600a5595945050505050565b60608260a0015163ffffffff1667ffffffffffffffff811115613f8c57613f8c614c62565b604051908082528060200260200182016040528015613fb5578160200160208202803683370190505b5090506000805b8460e00151518110156140b057600084905060208660e001518381518110613fe657613fe6615472565b602002602001015163ffffffff16901b8117905060005b6000828152600f602052604090205481101561409b576000828152600f6020526040902080548290811061403357614033615472565b9060005260206000200160009054906101000a90046001600160a01b031685858151811061406357614063615472565b6001600160a01b0390921660209283029190910190910152836140858161549e565b94505080806140939061549e565b915050613ffd565b505080806140a89061549e565b915050613fbc565b505092915050565b7aff00000000000000ff00000000000000ff00000000000000ff00006bffffffff0000000000000000604083901c9081167bffffffff00000000000000000000000000000000000000000000000084161760201c6fffffffff000000000000000000000000919091166001600160e01b031984161717601081901c9182167eff00000000000000ff00000000000000ff00000000000000ff000000000000821617600890811c7bff00000000000000ff00000000000000ff00000000000000ff000000939093167fff00000000000000ff00000000000000ff00000000000000ff000000000000009290921691909117919091179081901c7e0f000f000f000f000f000f000f000f000f000f000f000f000f000f000f000f167f0f000f000f000f000f000f000f000f000f000f000f000f000f000f000f000f00600492831c161790614224827f06060606060606060606060606060606060606060606060606060606060606066154d4565b901c7f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f16602761425491906157ba565b61427e827f30303030303030303030303030303030303030303030303030303030303030306154d4565b610be191906154d4565b60008390036142aa57604051637c946ed760e01b815260040160405180910390fd5b815115806142ba57508051825114155b156142e557815181516040516308151c1160e41b815260048101929092526024820152604401610cf7565b6000805b8351811015612624576142fd8260016154d4565b84828151811061430f5761430f615472565b602002602001015163ffffffff1610156143635783818151811061433557614335615472565b6020026020010151604051632ab10b0b60e21b8152600401610cf7919063ffffffff91909116815260200190565b83818151811061437557614375615472565b602002602001015163ffffffff16915080806143909061549e565b9150506142e9565b60008267ffffffffffffffff8111156143b3576143b3614c62565b6040519080825280602002602001820160405280156143dc578160200160208202803683370190505b5060e087015260005b8381101561456c578581815181106143ff576143ff615472565b60200260200101518760e00151828151811061441d5761441d615472565b63ffffffff909216602092830291909101820152865184919088908490811061444857614448615472565b602002602001015163ffffffff16901b8117905085828151811061446e5761446e615472565b6020908102919091018101516000838152600e8352604090208151815492909301516001600160601b0316640100000000026fffffffffffffffffffffffffffffffff1990921663ffffffff9093169290921717905585518690839081106144d8576144d8615472565b602002602001015160000151886080018181516144f591906157d1565b63ffffffff1690525085516001600160601b0384169087908490811061451d5761451d615472565b6020026020010151602001516001600160601b031611156145595785828151811061454a5761454a615472565b60200260200101516020015192505b50806145648161549e565b9150506143e5565b506001600160601b0381168652608086015160009061458c9060026157ee565b6145979060016157d1565b63ffffffff1690506145aa600382615824565b6000036145c3576145bc600382615838565b90506145dc565b6145ce600382615838565b6145d99060016154d4565b90505b80876060015163ffffffff1610806146075750866080015163ffffffff16876060015163ffffffff16115b15614646576060870151608088015160405163eb3a8ba360e01b815263ffffffff92831660048201526024810184905291166044820152606401610cf7565b50505050505050565b614659828261473f565b6001600160a01b0382163b1561473b57604051630a85bd0160e11b80825233600483015260006024830181905260448301849052608060648401526084830152906001600160a01b0384169063150b7a029060a4016020604051808303816000875af11580156146cd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906146f191906154b7565b6001600160e01b0319161461473b5760405162461bcd60e51b815260206004820152601060248201526f155394d0519157d49150d2541251539560821b6044820152606401610cf7565b5050565b6001600160a01b0382166147895760405162461bcd60e51b81526020600482015260116024820152701253959053125117d49150d25412515395607a1b6044820152606401610cf7565b6000818152600260205260409020546001600160a01b0316156147ee5760405162461bcd60e51b815260206004820152600e60248201527f414c52454144595f4d494e5445440000000000000000000000000000000000006044820152606401610cf7565b6001600160a01b038216600081815260036020908152604080832080546001019055848352600290915280822080546001600160a01b0319168417905551839291907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a45050565b50805460008255906000526020600020908101906148779190614947565b50565b828054828255906000526020600020906007016008900481019282156149195791602002820160005b838211156148e757835183826101000a81548163ffffffff021916908363ffffffff16021790555092602001926004016020816003010492830192600103026148a3565b80156149175782816101000a81549063ffffffff02191690556004016020816003010492830192600103026148e7565b505b50614925929150614977565b5090565b50805460008255906000526020600020908101906148779190614977565b5b8082111561492557805477ffffffffffffffffffffffffffffffffffffffffffffffff19168155600101614948565b5b808211156149255760008155600101614978565b6001600160e01b03198116811461487757600080fd5b6000602082840312156149b457600080fd5b81356149bf8161498c565b9392505050565b60005b838110156149e15781810151838201526020016149c9565b50506000910152565b60008151808452614a028160208601602086016149c6565b601f01601f19169290920160200192915050565b6020815260006149bf60208301846149ea565b600060208284031215614a3b57600080fd5b5035919050565b6001600160a01b038116811461487757600080fd5b60008060408385031215614a6a57600080fd5b8235614a7581614a42565b946020939093013593505050565b600060208284031215614a9557600080fd5b81356149bf81614a42565b6000604080830185845260208281860152818651808452606087019150828801935060005b81811015614af9578451805163ffffffff1684528401516001600160601b0316848401529383019391850191600101614ac5565b509098975050505050505050565b60008060408385031215614b1a57600080fd5b50508035926020909101359150565b600081518084526020808501945080840160005b83811015614b625781516001600160a01b031687529582019590820190600101614b3d565b509495945050505050565b828152604060208201526000614b866040830184614b29565b949350505050565b600080600060608486031215614ba357600080fd5b8335614bae81614a42565b92506020840135614bbe81614a42565b929592945050506040919091013590565b634e487b7160e01b600052602160045260246000fd5b60068110614c0357634e487b7160e01b600052602160045260246000fd5b9052565b6001600160601b03881681526001600160a01b03871660208201526040810186905263ffffffff85811660608301528481166080830152831660a082015260e08101614c5660c0830184614be5565b98975050505050505050565b634e487b7160e01b600052604160045260246000fd5b6040805190810167ffffffffffffffff81118282101715614c9b57614c9b614c62565b60405290565b604051601f8201601f1916810167ffffffffffffffff81118282101715614cca57614cca614c62565b604052919050565b600067ffffffffffffffff831115614cec57614cec614c62565b614cff601f8401601f1916602001614ca1565b9050828152838383011115614d1357600080fd5b828260208301376000602084830101529392505050565b600060208284031215614d3c57600080fd5b813567ffffffffffffffff811115614d5357600080fd5b8201601f81018413614d6457600080fd5b614b8684823560208401614cd2565b600067ffffffffffffffff821115614d8d57614d8d614c62565b5060051b60200190565b600082601f830112614da857600080fd5b81356020614dbd614db883614d73565b614ca1565b82815260059290921b84018101918181019086841115614ddc57600080fd5b8286015b84811015614e00578035614df381614a42565b8352918301918301614de0565b509695505050505050565b80356001600160601b03811681146115dc57600080fd5b600080600060608486031215614e3757600080fd5b833567ffffffffffffffff80821115614e4f57600080fd5b614e5b87838801614d97565b9450602091508186013581811115614e7257600080fd5b86019050601f81018713614e8557600080fd5b8035614e93614db882614d73565b81815260059190911b82018301908381019089831115614eb257600080fd5b928401925b82841015614ed757614ec884614e0b565b82529284019290840190614eb7565b96999698505050506040949094013593505050565b60008060408385031215614eff57600080fd5b8235614f0a81614a42565b915060208301358015158114614f1f57600080fd5b809150509250929050565b6000604082018483526020604081850152818551808452606086019150828701935060005b81811015614f6b57845183529383019391830191600101614f4f565b5090979650505050505050565b600080600080600060808688031215614f9057600080fd5b8535614f9b81614a42565b94506020860135614fab81614a42565b935060408601359250606086013567ffffffffffffffff80821115614fcf57600080fd5b818801915088601f830112614fe357600080fd5b813581811115614ff257600080fd5b89602082850101111561500457600080fd5b9699959850939650602001949392505050565b803563ffffffff811681146115dc57600080fd5b600082601f83011261503c57600080fd5b8135602061504c614db883614d73565b82815260059290921b8401810191818101908684111561506b57600080fd5b8286015b84811015614e005761508081615017565b835291830191830161506f565b600082601f83011261509e57600080fd5b813560206150ae614db883614d73565b82815260069290921b840181019181810190868411156150cd57600080fd5b8286015b84811015614e0057604081890312156150ea5760008081fd5b6150f2614c78565b6150fb82615017565b8152615108858301614e0b565b818601528352918301916040016150d1565b60008060008060008060c0878903121561513357600080fd5b863561513e81614a42565b955060208701359450604087013567ffffffffffffffff8082111561516257600080fd5b61516e8a838b0161502b565b9550606089013591508082111561518457600080fd5b5061519189828a0161508d565b9350506151a060808801615017565b915060a087013590509295509295509295565b600080600080608085870312156151c957600080fd5b84356151d481614a42565b935060208501359250604085013567ffffffffffffffff808211156151f857600080fd5b61520488838901614d97565b9350606087013591508082111561521a57600080fd5b506152278782880161502b565b91505092959194509250565b6000806040838503121561524657600080fd5b823561525181614a42565b91506020830135614f1f81614a42565b600081518084526020808501945080840160005b83811015614b6257815163ffffffff1687529582019590820190600101615275565b602081526001600160601b0382511660208201526001600160a01b03602083015116604082015260408201516060820152600060608301516152e1608084018263ffffffff169052565b50608083015163ffffffff811660a08401525060a083015163ffffffff811660c08401525060c083015161531860e0840182614be5565b5060e083015161010083810152614b86610120840182615261565b6000806000806080858703121561534957600080fd5b843561535481614a42565b935060208501359250604085013561536b81614a42565b9150606085013567ffffffffffffffff81111561538757600080fd5b8501601f8101871361539857600080fd5b61522787823560208401614cd2565b600080600080600060a086880312156153bf57600080fd5b85356153ca81614a42565b945060208601359350604086013567ffffffffffffffff808211156153ee57600080fd5b6153fa89838a0161502b565b9450606088013591508082111561541057600080fd5b5061541d8882890161508d565b92505061542c60808701615017565b90509295509295909350565b600181811c9082168061544c57607f821691505b60208210810361546c57634e487b7160e01b600052602260045260246000fd5b50919050565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b6000600182016154b0576154b0615488565b5060010190565b6000602082840312156154c957600080fd5b81516149bf8161498c565b80820180821115610be157610be1615488565b601f82111561142357600081815260208120601f850160051c8101602086101561550e5750805b601f850160051c820191505b8181101561552d5782815560010161551a565b505050505050565b815167ffffffffffffffff81111561554f5761554f614c62565b6155638161555d8454615438565b846154e7565b602080601f83116001811461559857600084156155805750858301515b600019600386901b1c1916600185901b17855561552d565b600085815260208120601f198616915b828110156155c7578886015182559484019460019091019084016155a8565b50858210156155e55787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6001600160601b0381811683821601908082111561561557615615615488565b5092915050565b6001600160601b0382811682821603908082111561561557615615615488565b63ffffffff82811682821603908082111561561557615615615488565b60006001600160a01b03808816835280871660208401525084604083015260806060830152826080830152828460a0840137600060a0848401015260a0601f19601f85011683010190509695505050505050565b60008086546156bb81615438565b600182811680156156d357600181146156e857615717565b60ff1984168752821515830287019450615717565b8a60005260208060002060005b8581101561570e5781548a8201529084019082016156f5565b50505082870194505b50505050855161572b818360208a016149c6565b019384525050602082015260400192915050565b600063ffffffff80831681810361575857615758615488565b6001019392505050565b6060815260006157756060830186614b29565b63ffffffff85166020840152828103604084015261579381856149ea565b9695505050505050565b6000602082840312156157af57600080fd5b81516149bf81614a42565b8082028115828204841417610be157610be1615488565b63ffffffff81811683821601908082111561561557615615615488565b63ffffffff8181168382160280821691908281146140b0576140b0615488565b634e487b7160e01b600052601260045260246000fd5b6000826158335761583361580e565b500690565b6000826158475761584761580e565b50049056fea2646970667358221220ee3dd136eb9c3aaae80969db0d981f4555af6520415662932908c79dee30e48b64736f6c63430008130033", + "deployedBytecode": "0x6080604052600436106103345760003560e01c806370a08231116101b0578063a60e4c3c116100ec578063dff7672411610095578063ef0e239b1161006f578063ef0e239b14610af7578063f908bc7714610b24578063fbdeb3d714610b44578063ffa1ad7414610b6457600080fd5b8063dff7672414610a96578063e23f6fb414610aa9578063e985e9c514610abc57600080fd5b8063c87b56dd116100c6578063c87b56dd14610a36578063cbf994f814610a56578063ccc9305d14610a7657600080fd5b8063a60e4c3c146109c8578063a6f9dae1146109f6578063b88d4fde14610a1657600080fd5b80638a2bd86f116101595780639890220b116101335780639890220b1461093c578063a22cb46514610951578063a3fbbaae14610971578063a5d059ca1461099157600080fd5b80638a2bd86f146108c25780638da5cb5b1461090757806395d89b411461092757600080fd5b80637c5e63e01161018a5780637c5e63e01461084d57806382694b1d1461088257806386a2bdd4146108a257600080fd5b806370a08231146107c9578063718934d8146107e957806373b8b6a21461082d57600080fd5b806342842e0e1161027f57806355f804b3116102285780636352211e116102025780636352211e1461070a57806363dd76151461072a5780636c0360eb146107945780636f99f15c146107a957600080fd5b806355f804b3146106a357806357838e85146106c35780635e4507fa146106ea57600080fd5b80634eb780da116102595780634eb780da1461062d5780634f558e79146106635780634f6ccce71461068357600080fd5b806342842e0e146105cd578063481c6a75146105ed5780634d486f851461060d57600080fd5b806318160ddd116102e157806323b872dd116102bb57806323b872dd146104d057806342144854146104f05780634236aff81461053e57600080fd5b806318160ddd146104505780631de286ba1461047457806321e4f7bb146104a257600080fd5b8063095ea7b311610312578063095ea7b3146103de57806310c6aa191461040057806317351f7e1461042057600080fd5b806301ffc9a71461033957806306fdde031461036e578063081812fc14610390575b600080fd5b34801561034557600080fd5b506103596103543660046149a2565b610b95565b60405190151581526020015b60405180910390f35b34801561037a57600080fd5b50610383610be7565b6040516103659190614a16565b34801561039c57600080fd5b506103c66103ab366004614a29565b6004602052600090815260409020546001600160a01b031681565b6040516001600160a01b039091168152602001610365565b3480156103ea57600080fd5b506103fe6103f9366004614a57565b610c75565b005b34801561040c57600080fd5b506103fe61041b366004614a83565b610d5c565b34801561042c57600080fd5b5061035961043b366004614a83565b60126020526000908152604090205460ff1681565b34801561045c57600080fd5b5061046660095481565b604051908152602001610365565b34801561048057600080fd5b5061049461048f366004614a29565b610e15565b604051610365929190614aa0565b3480156104ae57600080fd5b506104c26104bd366004614b07565b61106b565b604051610365929190614b6d565b3480156104dc57600080fd5b506103fe6104eb366004614b8e565b611159565b3480156104fc57600080fd5b5061052661050b366004614a29565b6010602052600090815260409020546001600160601b031681565b6040516001600160601b039091168152602001610365565b34801561054a57600080fd5b506105ba610559366004614a29565b6013602052600090815260409020805460018201546002909201546001600160601b03821692600160601b928390046001600160a01b031692909163ffffffff808216926401000000008304821692600160401b8104909216910460ff1687565b6040516103659796959493929190614c07565b3480156105d957600080fd5b506103fe6105e8366004614b8e565b611333565b3480156105f957600080fd5b506007546103c6906001600160a01b031681565b34801561061957600080fd5b506104c2610628366004614a29565b611428565b34801561063957600080fd5b506103c6610648366004614a83565b6011602052600090815260409020546001600160a01b031681565b34801561066f57600080fd5b5061035961067e366004614a29565b61157a565b34801561068f57600080fd5b5061046661069e366004614a29565b61159c565b3480156106af57600080fd5b506103fe6106be366004614d2a565b6115e1565b3480156106cf57600080fd5b50600b546103c690600160601b90046001600160a01b031681565b3480156106f657600080fd5b506103c6610705366004614b07565b61168a565b34801561071657600080fd5b506103c6610725366004614a29565b6116c2565b34801561073657600080fd5b50610770610745366004614a29565b600e6020526000908152604090205463ffffffff81169064010000000090046001600160601b031682565b6040805163ffffffff90931683526001600160601b03909116602083015201610365565b3480156107a057600080fd5b50610383611727565b3480156107b557600080fd5b50600b54610526906001600160601b031681565b3480156107d557600080fd5b506104666107e4366004614a83565b611734565b3480156107f557600080fd5b50610809610804366004614b07565b6117a8565b604080516001600160a01b03909316835263ffffffff909116602083015201610365565b34801561083957600080fd5b50610359610848366004614e22565b6117ee565b34801561085957600080fd5b506103836040518060400160405280600981526020016806630313730313232360bc1b81525081565b34801561088e57600080fd5b5061035961089d366004614eec565b611c43565b3480156108ae57600080fd5b506104666108bd366004614b07565b611cdc565b3480156108ce57600080fd5b506104666108dd366004614a57565b60a01b6001600160a01b03909116176000908152601060205260409020546001600160601b031690565b34801561091357600080fd5b506006546103c6906001600160a01b031681565b34801561093357600080fd5b50610383611d0d565b34801561094857600080fd5b50610466611d1a565b34801561095d57600080fd5b506103fe61096c366004614eec565b611e78565b34801561097d57600080fd5b506103fe61098c366004614a83565b611ee4565b34801561099d57600080fd5b506109b16109ac366004614a57565b611f95565b604080519215158352602083019190915201610365565b3480156109d457600080fd5b506109e86109e3366004614a29565b612431565b604051610365929190614f2a565b348015610a0257600080fd5b506103fe610a11366004614a83565b612495565b348015610a2257600080fd5b506103fe610a31366004614f78565b612546565b348015610a4257600080fd5b50610383610a51366004614a29565b61262b565b348015610a6257600080fd5b50610359610a7136600461511a565b6126a5565b348015610a8257600080fd5b506109b1610a91366004614a57565b612c33565b610359610aa43660046151b3565b612f95565b610359610ab7366004614a57565b613590565b348015610ac857600080fd5b50610359610ad7366004615233565b600560209081526000928352604080842090915290825290205460ff1681565b348015610b0357600080fd5b50610b17610b12366004614a29565b61370f565b6040516103659190615297565b348015610b3057600080fd5b506103c6610b3f366004615333565b61388f565b348015610b5057600080fd5b50610466610b5f3660046153a7565b613c60565b348015610b7057600080fd5b50610383604051806040016040528060058152602001640312e302e360dc1b81525081565b60006301ffc9a760e01b6001600160e01b031983161480610bc657506380ac58cd60e01b6001600160e01b03198316145b80610be15750635b5e139f60e01b6001600160e01b03198316145b92915050565b60008054610bf490615438565b80601f0160208091040260200160405190810160405280929190818152602001828054610c2090615438565b8015610c6d5780601f10610c4257610100808354040283529160200191610c6d565b820191906000526020600020905b815481529060010190602001808311610c5057829003601f168201915b505050505081565b6000818152600260205260409020546001600160a01b031633811480610cbe57506001600160a01b038116600090815260056020908152604080832033845290915290205460ff165b610d005760405162461bcd60e51b815260206004820152600e60248201526d1393d517d055551213d49256915160921b60448201526064015b60405180910390fd5b60008281526004602052604080822080546001600160a01b0319166001600160a01b0387811691821790925591518593918516917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591a4505050565b6006546001600160a01b03163314610d9c5760065460405163521eb56d60e11b81523360048201526001600160a01b039091166024820152604401610cf7565b6001600160a01b038116610dc35760405163d92e233d60e01b815260040160405180910390fd5b600b80546001600160601b0316600160601b6001600160a01b038416908102919091179091556040517f8d1e8547016120917daad7f81c42b48f7fee379badc48f1889f0f43bb619472590600090a250565b600081815260136020908152604080832081516101008101835281546001600160601b03811682526001600160a01b03600160601b918290041694820194909452600182015492810192909252600281015463ffffffff808216606085810191909152640100000000830482166080860152600160401b830490911660a0850152938593929160c084019160ff9104166005811115610eb657610eb6614bcf565b6005811115610ec757610ec7614bcf565b815260200160038201805480602002602001604051908101604052809291908181526020018280548015610f4657602002820191906000526020600020906000905b82829054906101000a900463ffffffff1663ffffffff1681526020019060040190602082600301049283019260010382029150808411610f095790505b50505050508152505090508060e001515192508267ffffffffffffffff811115610f7257610f72614c62565b604051908082528060200260200182016040528015610fb757816020015b6040805180820190915260008082526020820152815260200190600190039081610f905790505b50915060005b8381101561106457600085905060208360e001518381518110610fe257610fe2615472565b60209081029190910181015163ffffffff90811690921b929092176000818152600e845260409081902081518083019092525492831681526401000000009092046001600160601b031692820192909252845185908490811061104757611047615472565b6020026020010181905250508061105d9061549e565b9050610fbd565b5050915091565b602081811b83176000818152600f909252604090912054906060908267ffffffffffffffff81111561109f5761109f614c62565b6040519080825280602002602001820160405280156110c8578160200160208202803683370190505b50915060005b83811015611150576000828152600f602052604090208054829081106110f6576110f6615472565b9060005260206000200160009054906101000a90046001600160a01b031683828151811061112657611126615472565b6001600160a01b0390921660209283029190910190910152806111488161549e565b9150506110ce565b50509250929050565b6000818152600260205260409020546001600160a01b038481169116146111c25760405162461bcd60e51b815260206004820152600a60248201527f57524f4e475f46524f4d000000000000000000000000000000000000000000006044820152606401610cf7565b6001600160a01b03821661120c5760405162461bcd60e51b81526020600482015260116024820152701253959053125117d49150d25412515395607a1b6044820152606401610cf7565b336001600160a01b038416148061124657506001600160a01b038316600090815260056020908152604080832033845290915290205460ff165b8061126757506000818152600460205260409020546001600160a01b031633145b6112a45760405162461bcd60e51b815260206004820152600e60248201526d1393d517d055551213d49256915160921b6044820152606401610cf7565b6001600160a01b0380841660008181526003602090815260408083208054600019019055938616808352848320805460010190558583526002825284832080546001600160a01b03199081168317909155600490925284832080549092169091559251849392917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91a4505050565b61133e838383611159565b6001600160a01b0382163b1561142357604051630a85bd0160e11b8082523360048301526001600160a01b03858116602484015260448301849052608060648401526000608484015290919084169063150b7a029060a4016020604051808303816000875af11580156113b5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113d991906154b7565b6001600160e01b031916146114235760405162461bcd60e51b815260206004820152601060248201526f155394d0519157d49150d2541251539560821b6044820152606401610cf7565b505050565b600081815260136020908152604080832081516101008101835281546001600160601b03811682526001600160a01b03600160601b918290041694820194909452600182015492810192909252600281015463ffffffff808216606085810191909152640100000000830482166080860152600160401b830490911660a0850152938593929160c084019160ff91041660058111156114c9576114c9614bcf565b60058111156114da576114da614bcf565b81526020016003820180548060200260200160405190810160405280929190818152602001828054801561155957602002820191906000526020600020906000905b82829054906101000a900463ffffffff1663ffffffff168152602001906004019060208260030104928301926001038202915080841161151c5790505b505050505081525050905061156e8185613f67565b91508151925050915091565b60008082118015610be157506009546115949060016154d4565b821092915050565b60006115a98260016154d4565b90506009548111156115dc57600954604051637ae5968560e01b8152610cf7918391600401918252602082015260400190565b919050565b6006546001600160a01b031633146116215760065460405163521eb56d60e11b81523360048201526001600160a01b039091166024820152604401610cf7565b805160000361164357604051637c946ed760e01b815260040160405180910390fd5b600861164f8282615535565b507f5411e8ebf1636d9e83d5fc4900bf80cbac82e8790da2a4c94db4895e889eedf68160405161167f9190614a16565b60405180910390a150565b600f60205281600052604060002081815481106116a657600080fd5b6000918252602090912001546001600160a01b03169150829050565b6000818152600260205260409020546001600160a01b0316806115dc5760405162461bcd60e51b815260206004820152600a60248201527f4e4f545f4d494e544544000000000000000000000000000000000000000000006044820152606401610cf7565b60088054610bf490615438565b60006001600160a01b03821661178c5760405162461bcd60e51b815260206004820152600c60248201527f5a45524f5f4144445245535300000000000000000000000000000000000000006044820152606401610cf7565b506001600160a01b031660009081526003602052604090205490565b600d60205281600052604060002081815481106117c457600080fd5b6000918252602090912001546001600160a01b0381169250600160a01b900463ffffffff16905082565b600081815260136020908152604080832081516101008101835281546001600160601b0381168252600160601b908190046001600160a01b031694820194909452600182015492810192909252600281015463ffffffff8082166060850152640100000000820481166080850152600160401b82041660a0840152849360c08401910460ff16600581111561188557611885614bcf565b600581111561189657611896614bcf565b81526020016003820180548060200260200160405190810160405280929190818152602001828054801561191557602002820191906000526020600020906000905b82829054906101000a900463ffffffff1663ffffffff16815260200190600401906020826003010492830192600103820291508084116118d85790505b50505050508152505090506004600581111561193357611933614bcf565b8160c00151600581111561194957611949614bcf565b14611988578060c00151600581111561196457611964614bcf565b604051633c053f9d60e21b8152600481019190915260248101849052604401610cf7565b83518551146119b757845184516040516308151c1160e41b815260048101929092526024820152604401610cf7565b80602001516001600160a01b0316336001600160a01b031614611a0b5760208101516040516379f91cd360e01b81523360048201526001600160a01b03909116602482015260448101849052606401610cf7565b845160005b81811015611c3657600060116000898481518110611a3057611a30615472565b6020908102919091018101516001600160a01b03908116835282820193909352604091820160009081205490931660a08a901b81178085526010909252919092205489519193506001600160601b03169081908a9086908110611a9557611a95615472565b60200260200101516001611aa991906155f5565b6001600160601b03161115611b0357600b8054829190600090611ad69084906001600160601b03166155f5565b92506101000a8154816001600160601b0302191690836001600160601b0316021790555060009050611b87565b888481518110611b1557611b15615472565b6020908102919091010151600b8054600090611b3b9084906001600160601b03166155f5565b92506101000a8154816001600160601b0302191690836001600160601b03160217905550888481518110611b7157611b71615472565b602002602001015181611b84919061561c565b90505b600082815260106020526040902080546bffffffffffffffffffffffff19166001600160601b038316179055885188906001600160a01b038516907fa2e524bd0f71903485fbb3d6d50cb305f61005ceea2047c3ac92aa7e0d104306908c9088908110611bf657611bf6615472565b6020026020010151604051611c1a91906001600160601b0391909116815260200190565b60405180910390a350505080611c2f9061549e565b9050611a10565b5060019695505050505050565b6006546000906001600160a01b03163314611c865760065460405163521eb56d60e11b81523360048201526001600160a01b039091166024820152604401610cf7565b6001600160a01b038316611cad5760405163d92e233d60e01b815260040160405180910390fd5b506001600160a01b03919091166000908152601260205260409020805460ff1916911515919091179055600190565b600c6020528160005260406000208181548110611cf857600080fd5b90600052602060002001600091509150505481565b60018054610bf490615438565b60006001600a541115611d40576040516345f5ce8b60e11b815260040160405180910390fd5b6002600a55600b54600160601b90046001600160a01b03163314611d9257600b5460405163312d21ff60e11b8152336004820152600160601b9091046001600160a01b03166024820152604401610cf7565b50600b546001600160601b03168015611e7057600b80546bffffffffffffffffffffffff19169055604051600090339083908381818185875af1925050503d8060008114611dfc576040519150601f19603f3d011682016040523d82523d6000602084013e611e01565b606091505b5050905080611e395760405163cd3f165960e01b81526000600482015230602482015233604482015260648101839052608401610cf7565b60405182815233907ff36f4d6622e16a536bbb049064af779cdd483a0b388d347d3752a65f1058bf5b9060200160405180910390a2505b6001600a5590565b3360008181526005602090815260408083206001600160a01b03871680855290835292819020805460ff191686151590811790915590519081529192917f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a35050565b6006546001600160a01b03163314611f245760065460405163521eb56d60e11b81523360048201526001600160a01b039091166024820152604401610cf7565b6001600160a01b038116611f4b5760405163d92e233d60e01b815260040160405180910390fd5b600780546001600160a01b0319166001600160a01b0383169081179091556040517f2c1c11af44aa5608f1dca38c00275c30ea091e02417d36e70e9a1538689c433d90600090a250565b6000806001600a541115611fbc576040516345f5ce8b60e11b815260040160405180910390fd5b6002600a556007546001600160a01b031633146120015760075460405163312d21ff60e11b81523360048201526001600160a01b039091166024820152604401610cf7565b6001600160a01b0384166120285760405163d92e233d60e01b815260040160405180910390fd5b600083815260136020526040902060056002820154600160601b900460ff16600581111561205857612058614bcf565b146120a1576002810154600160601b900460ff16600581111561207d5761207d614bcf565b604051633c053f9d60e21b8152600481019190915260248101859052604401610cf7565b60a084901b6001600160a01b038616176000818152600d6020908152604080832080548251818502810185019093528083529192909190849084015b8282101561212957600084815260209081902060408051808201909152908401546001600160a01b0381168252600160a01b900463ffffffff16818301528252600190920191016120dd565b50508251929350505060008190036121665760405163df2ddd7360e01b81526001600160a01b038916600482015260248101889052604401610cf7565b808460020160088282829054906101000a900463ffffffff16612189919061563c565b92506101000a81548163ffffffff021916908363ffffffff1602179055508360020160089054906101000a900463ffffffff1663ffffffff166000036121df5760028401805460ff60601b1916600160601b1790555b60005b818110156122a7576000889050602084838151811061220357612203615472565b60209081029190910181015181015163ffffffff1690911b919091176000818152600e90925260409091205461224a9064010000000090046001600160601b0316886154d4565b96506011600085848151811061226257612262615472565b602090810291909101810151516001600160a01b0316825281019190915260400160002080546001600160a01b0319169055508061229f8161549e565b9150506121e2565b506000838152600d602052604081206122bf91614859565b6000838152601060205260409020546001600160601b0316808611156122ec57806001600160601b031695505b85156123e55760008481526010602052604080822080546bffffffffffffffffffffffff19169055516001600160a01b038b169088908381818185875af1925050503d806000811461235a576040519150601f19603f3d011682016040523d82523d6000602084013e61235f565b606091505b50509050806123a05760405163cd3f165960e01b8152600060048201523060248201526001600160a01b038b16604482015260648101889052608401610cf7565b896001600160a01b03167fbb28353e4598c3b9199101a66e0989549b659a59a54d2c27fbb183f1932c8e6d886040516123db91815260200190565b60405180910390a2505b60405188906001600160a01b038b16907f5ebf7fe30be09f0f03b9195632508d95c8b67bf010c93abda67f70d5d9599d1e90600090a350506001600a8190559793965092945050505050565b6000818152600c60209081526040808320805482518185028101850190935280835260609383018282801561248557602002820191906000526020600020905b815481526020019060010190808311612471575b5050505050905080519150915091565b6006546001600160a01b031633146124d55760065460405163521eb56d60e11b81523360048201526001600160a01b039091166024820152604401610cf7565b6001600160a01b0381166124fc5760405163d92e233d60e01b815260040160405180910390fd5b600680546001600160a01b0319166001600160a01b0383169081179091556040517f4ffd725fc4a22075e9ec71c59edf9c38cdeb588a91b24fc5b61388c5be41282b90600090a250565b612551858585611159565b6001600160a01b0384163b1561262457604051630a85bd0160e11b808252906001600160a01b0386169063150b7a02906125979033908a90899089908990600401615659565b6020604051808303816000875af11580156125b6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125da91906154b7565b6001600160e01b031916146126245760405162461bcd60e51b815260206004820152601060248201526f155394d0519157d49150d2541251539560821b6044820152606401610cf7565b5050505050565b6000818152601360205260408120600101546060915060086040518060400160405280600981526020016806630313730313232360bc1b81525061266e836140b8565b61267b608085901b6140b8565b60405160200161268e94939291906156ad565b604051602081830303815290604052915050919050565b6007546000906001600160a01b031633146126e85760075460405163312d21ff60e11b81523360048201526001600160a01b039091166024820152604401610cf7565b60006126f3836116c2565b9050876001600160a01b0316816001600160a01b03161461273a5760405163521eb56d60e11b81526001600160a01b03808a16600483015282166024820152604401610cf7565b600083815260136020908152604080832081516101008101835281546001600160601b03811682526001600160a01b03600160601b918290041694820194909452600182015492810192909252600281015463ffffffff8082166060850152640100000000820481166080850152600160401b82041660a08401529192909160c084019160ff91041660058111156127d4576127d4614bcf565b60058111156127e5576127e5614bcf565b81526020016003820180548060200260200160405190810160405280929190818152602001828054801561286457602002820191906000526020600020906000905b82829054906101000a900463ffffffff1663ffffffff16815260200190600401906020826003010492830192600103820291508084116128275790505b50505050508152505090506001600581111561288257612882614bcf565b8160c00151600581111561289857612898614bcf565b146128b3578060c00151600581111561207d5761207d614bcf565b6128be888888614288565b63ffffffff85166060820152600060808201819052875167ffffffffffffffff8111156128ed576128ed614c62565b604051908082528060200260200182016040528015612916578160200160208202803683370190505b5090506000885167ffffffffffffffff81111561293557612935614c62565b60405190808252806020026020018201604052801561297a57816020015b60408051808201909152600080825260208201528152602001906001900390816129535790505b5090506000805b8a51811015612aaf5789818151811061299c5761299c615472565b60200260200101516000015163ffffffff16600003612a1157600088905060208c83815181106129ce576129ce615472565b60209081029190910181015163ffffffff1690911b919091176000908152600e9091526040902080546fffffffffffffffffffffffffffffffff19169055612a9d565b8a8181518110612a2357612a23615472565b6020026020010151848381518110612a3d57612a3d615472565b602002602001019063ffffffff16908163ffffffff1681525050898181518110612a6957612a69615472565b6020026020010151838381518110612a8357612a83615472565b60200260200101819052508180612a999061549e565b9250505b80612aa78161549e565b915050612981565b5060408401518b8114612ae6576000888152600c602090815260408083208054600181018255908452919092200182905585018c90525b612af3858585858c614398565b6000888152601360209081526040918290208751918801516001600160a01b0316600160601b9081026001600160601b03909316929092178155918701516001830155606087015160028301805460808a015160a08b015163ffffffff908116600160401b026bffffffff0000000000000000199282166401000000000267ffffffffffffffff199094169190951617919091179081168317825560c08a01518a9594909360ff60601b19166cffffffffff0000000000000000199092169190911790836005811115612bc857612bc8614bcf565b021790555060e08201518051612be891600384019160209091019061487a565b50506040518d81528991507fff312ce131c4d73ac90ece91266be7090486c5e15f78b7ea2b108c36dfd475299060200160405180910390a25060019c9b505050505050505050505050565b6000806001600a541115612c5a576040516345f5ce8b60e11b815260040160405180910390fd5b6002600a556007546001600160a01b03163314612c9f5760075460405163312d21ff60e11b81523360048201526001600160a01b039091166024820152604401610cf7565b6000612caa846116c2565b9050846001600160a01b0316816001600160a01b031614612cf15760405163521eb56d60e11b81526001600160a01b03808716600483015282166024820152604401610cf7565b600084815260136020526040902060016002820154600160601b900460ff166005811115612d2157612d21614bcf565b1480612d4c575060056002820154600160601b900460ff166005811115612d4a57612d4a614bcf565b145b15612d95576002810154600160601b900460ff166005811115612d7157612d71614bcf565b604051633c053f9d60e21b8152600481019190915260248101869052604401610cf7565b6002810154600160401b900463ffffffff1615612dcf5760028101805460ff60601b19166c05000000000000000000000000179055612de5565b60028101805460ff60601b1916600160601b1790555b60005b6003820154811015612e725760008690506020836003018381548110612e1057612e10615472565b90600052602060002090600891828204019190066004029054906101000a900463ffffffff1663ffffffff16901b81179050600f60008281526020019081526020016000206000612e619190614929565b50612e6b8161549e565b9050612de8565b5080546040516001600160601b0390911693506000906001600160a01b0388169085908381818185875af1925050503d8060008114612ecd576040519150601f19603f3d011682016040523d82523d6000602084013e612ed2565b606091505b5050905080612f135760405163cd3f165960e01b8152600060048201523060248201526001600160a01b038816604482015260648101859052608401610cf7565b866001600160a01b03167fbb28353e4598c3b9199101a66e0989549b659a59a54d2c27fbb183f1932c8e6d85604051612f4e91815260200190565b60405180910390a260405186907fe45f5b9540df4f71b7e044809fa318806328c1ea2388a70c7373d97ccf8a0faa90600090a250506001600a819055959194509092505050565b6007546000906001600160a01b03163314612fd85760075460405163312d21ff60e11b81523360048201526001600160a01b039091166024820152604401610cf7565b815183511461300757825182516040516308151c1160e41b815260048101929092526024820152604401610cf7565b6000848152601360205260409020600280820154600160601b900460ff16600581111561303657613036614bcf565b1461305b576002810154600160601b900460ff166005811115612d7157612d71614bcf565b83516000805b82811015613150576000889050602087838151811061308257613082615472565b60209081029190910181015163ffffffff90811690921b929092176000818152600e845260408082208151808301909252549384168082526401000000009094046001600160601b0316948101949094529092919003613123578783815181106130ee576130ee615472565b60200260200101518a6040516332832be560e21b8152600401610cf792919063ffffffff929092168252602082015260400190565b602081015161313b906001600160601b0316856154d4565b93505050806131499061549e565b9050613061565b5080341461318157604051637ebbcab960e11b81523460048201526024810182905260448101889052606401610cf7565b6001600160a01b0388811660009081526011602052604090205416156131bd576040516322ddebd960e21b815260048101889052602401610cf7565b60a087901b6001600160a01b0389161760005b838110156134b15760008882815181106131ec576131ec615472565b60200260200101519050600088838151811061320a5761320a615472565b60200260200101519050816001600160a01b03168c6001600160a01b031603613249576040516322ddebd960e21b8152600481018c9052602401610cf7565b6001600160a01b0382811660009081526011602052604090205416156132a0576001600160a01b038281166000908152601160205260409081902054905163631695bd60e01b815291166004820152602401610cf7565b60008b905060208a85815181106132b9576132b9615472565b60209081029190910181015163ffffffff90811690921b929092176000818152600e8452604080822054600f90955290205490929091169003613312576040516304ad100760e21b8152600481018d9052602401610cf7565b6000818152600f602090815260408083208054600181810183559185528385200180546001600160a01b03808a166001600160a01b031990921682179092558a8652600d8552838620845180860190955290845263ffffffff8089168587019081528254948501835591875294909520925192909101805494518416600160a01b0277ffffffffffffffffffffffffffffffffffffffffffffffff19909516929091169190911792909217909155600289018054600160401b90049091169060086133dc8361573f565b91906101000a81548163ffffffff021916908363ffffffff160217905550508c60116000856001600160a01b03166001600160a01b0316815260200190815260200160002060006101000a8154816001600160a01b0302191690836001600160a01b03160217905550826001600160a01b03168c8e6001600160a01b03167f6835389a6da5341647f18cbe0a89c56f473f4c17bfaee6e6d07d61f1928e0b7c85604051613495919063ffffffff91909116815260200190565b60405180910390a4505050806134aa9061549e565b90506131d0565b50600284015463ffffffff64010000000082048116600160401b90920416036134f35760028401805460ff60601b19166c030000000000000000000000001790555b6000818152601060205260408120805434929061351a9084906001600160601b03166155f5565b92506101000a8154816001600160601b0302191690836001600160601b03160217905550886001600160a01b03167fe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c3460405161357991815260200190565b60405180910390a250600198975050505050505050565b6007546000906001600160a01b031633146135d35760075460405163312d21ff60e11b81523360048201526001600160a01b039091166024820152604401610cf7565b60006135de836116c2565b9050836001600160a01b0316816001600160a01b0316146136255760405163521eb56d60e11b81526001600160a01b03808616600483015282166024820152604401610cf7565b600083815260136020526040902060016002820154600160601b900460ff16600581111561365557613655614bcf565b1461367657604051635960d22f60e11b815260048101859052602401610cf7565b80546001600160601b031634146136bb578054604051631c30abbb60e31b81523460048201526001600160601b03909116602482015260448101859052606401610cf7565b60028101805460ff60601b19166c0200000000000000000000000017905560405184907fa48b531f972c0e4aca57afcc5c099c52a7bd21bc5e2a1b733eec3be9e88da97a90600090a2506001949350505050565b6137576040805161010081018252600080825260208201819052918101829052606081018290526080810182905260a081018290529060c08201908152602001606081525090565b60008281526013602090815260409182902082516101008101845281546001600160601b0381168252600160601b908190046001600160a01b031693820193909352600182015493810193909352600281015463ffffffff8082166060860152640100000000820481166080860152600160401b82041660a0850152909160c08401910460ff1660058111156137ef576137ef614bcf565b600581111561380057613800614bcf565b81526020016003820180548060200260200160405190810160405280929190818152602001828054801561387f57602002820191906000526020600020906000905b82829054906101000a900463ffffffff1663ffffffff16815260200190600401906020826003010492830192600103820291508084116138425790505b5050505050815250509050919050565b60006001600a5411156138b5576040516345f5ce8b60e11b815260040160405180910390fd5b6002600a556007546001600160a01b031633146138fa5760075460405163312d21ff60e11b81523360048201526001600160a01b039091166024820152604401610cf7565b6000613905856116c2565b9050856001600160a01b0316816001600160a01b03161461394c5760405163521eb56d60e11b81526001600160a01b03808816600483015282166024820152604401610cf7565b6001600160a01b03841660009081526012602052604090205460ff1661398f5760405162a2307960e51b81526001600160a01b0385166004820152602401610cf7565b600085815260136020526040902060036002820154600160601b900460ff1660058111156139bf576139bf614bcf565b14613a08576002810154600160601b900460ff1660058111156139e4576139e4614bcf565b604051633c053f9d60e21b8152600481019190915260248101879052604401610cf7565b604080516101008101825282546001600160601b0381168252600160601b908190046001600160a01b03166020830152600184015492820192909252600283015463ffffffff8082166060840152640100000000820481166080840152600160401b82041660a0830152600092613b359291859160c08401910460ff166005811115613a9657613a96614bcf565b6005811115613aa757613aa7614bcf565b815260200160038201805480602002602001604051908101604052809291908181526020018280548015613b2657602002820191906000526020600020906000905b82829054906101000a900463ffffffff1663ffffffff1681526020019060040190602082600301049283019260010382029150808411613ae95790505b50505050508152505088613f67565b6002830154604051631e731b7560e31b81529192506001600160a01b0388169163f398dba891613b7291859163ffffffff16908a90600401615762565b6020604051808303816000875af1158015613b91573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613bb5919061579d565b82546001600160601b0316600160601b6001600160a01b03831690810291909117845560028401805460ff60601b19166c040000000000000000000000001790556040519195509088907f2d53f895cd5faf3cddba94a25c2ced2105885b5b37450ff430ffa3cbdf332c7490600090a360405187907fa133ed72c03a7d008deaae618a61613c4fd41c67bba1cad1a6bc0a1c5a9c156e90600090a250506001600a5550949350505050565b60006001600a541115613c86576040516345f5ce8b60e11b815260040160405180910390fd5b6002600a556007546001600160a01b03163314613ccb5760075460405163312d21ff60e11b81523360048201526001600160a01b039091166024820152604401610cf7565b6001600160a01b038616613cf25760405163d92e233d60e01b815260040160405180910390fd5b613cfd858585614288565b60005b8451811015613d9157838181518110613d1b57613d1b615472565b60200260200101516000015163ffffffff1660001480613d615750838181518110613d4857613d48615472565b6020026020010151602001516001600160601b03166000145b15613d7f57604051637c946ed760e01b815260040160405180910390fd5b80613d898161549e565b915050613d00565b505060095480613da08161549e565b915050613deb6040805161010081018252600080825260208201819052918101829052606081018290526080810182905260a081018290529060c08201908152602001606081525090565b63ffffffff8316606082015260408101869052600160c082018181525050613e17818686885186614398565b6000828152601360209081526040918290208351918401516001600160a01b0316600160601b9081026001600160601b039093169290921781559183015160018301556060830151600283018054608086015160a087015163ffffffff908116600160401b026bffffffff0000000000000000199282166401000000000267ffffffffffffffff199094169190951617919091179081168317825560c0860151869594909360ff60601b19166cffffffffff0000000000000000199092169190911790836005811115613eec57613eec614bcf565b021790555060e08201518051613f0c91600384019160209091019061487a565b5050506009829055613f1e878361464f565b817fb34c1e02384201736eb4693b9b173306cb41bff12f15894dea5773088e9a3b1c87604051613f5091815260200190565b60405180910390a2506001600a5595945050505050565b60608260a0015163ffffffff1667ffffffffffffffff811115613f8c57613f8c614c62565b604051908082528060200260200182016040528015613fb5578160200160208202803683370190505b5090506000805b8460e00151518110156140b057600084905060208660e001518381518110613fe657613fe6615472565b602002602001015163ffffffff16901b8117905060005b6000828152600f602052604090205481101561409b576000828152600f6020526040902080548290811061403357614033615472565b9060005260206000200160009054906101000a90046001600160a01b031685858151811061406357614063615472565b6001600160a01b0390921660209283029190910190910152836140858161549e565b94505080806140939061549e565b915050613ffd565b505080806140a89061549e565b915050613fbc565b505092915050565b7aff00000000000000ff00000000000000ff00000000000000ff00006bffffffff0000000000000000604083901c9081167bffffffff00000000000000000000000000000000000000000000000084161760201c6fffffffff000000000000000000000000919091166001600160e01b031984161717601081901c9182167eff00000000000000ff00000000000000ff00000000000000ff000000000000821617600890811c7bff00000000000000ff00000000000000ff00000000000000ff000000939093167fff00000000000000ff00000000000000ff00000000000000ff000000000000009290921691909117919091179081901c7e0f000f000f000f000f000f000f000f000f000f000f000f000f000f000f000f167f0f000f000f000f000f000f000f000f000f000f000f000f000f000f000f000f00600492831c161790614224827f06060606060606060606060606060606060606060606060606060606060606066154d4565b901c7f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f16602761425491906157ba565b61427e827f30303030303030303030303030303030303030303030303030303030303030306154d4565b610be191906154d4565b60008390036142aa57604051637c946ed760e01b815260040160405180910390fd5b815115806142ba57508051825114155b156142e557815181516040516308151c1160e41b815260048101929092526024820152604401610cf7565b6000805b8351811015612624576142fd8260016154d4565b84828151811061430f5761430f615472565b602002602001015163ffffffff1610156143635783818151811061433557614335615472565b6020026020010151604051632ab10b0b60e21b8152600401610cf7919063ffffffff91909116815260200190565b83818151811061437557614375615472565b602002602001015163ffffffff16915080806143909061549e565b9150506142e9565b60008267ffffffffffffffff8111156143b3576143b3614c62565b6040519080825280602002602001820160405280156143dc578160200160208202803683370190505b5060e087015260005b8381101561456c578581815181106143ff576143ff615472565b60200260200101518760e00151828151811061441d5761441d615472565b63ffffffff909216602092830291909101820152865184919088908490811061444857614448615472565b602002602001015163ffffffff16901b8117905085828151811061446e5761446e615472565b6020908102919091018101516000838152600e8352604090208151815492909301516001600160601b0316640100000000026fffffffffffffffffffffffffffffffff1990921663ffffffff9093169290921717905585518690839081106144d8576144d8615472565b602002602001015160000151886080018181516144f591906157d1565b63ffffffff1690525085516001600160601b0384169087908490811061451d5761451d615472565b6020026020010151602001516001600160601b031611156145595785828151811061454a5761454a615472565b60200260200101516020015192505b50806145648161549e565b9150506143e5565b506001600160601b0381168652608086015160009061458c9060026157ee565b6145979060016157d1565b63ffffffff1690506145aa600382615824565b6000036145c3576145bc600382615838565b90506145dc565b6145ce600382615838565b6145d99060016154d4565b90505b80876060015163ffffffff1610806146075750866080015163ffffffff16876060015163ffffffff16115b15614646576060870151608088015160405163eb3a8ba360e01b815263ffffffff92831660048201526024810184905291166044820152606401610cf7565b50505050505050565b614659828261473f565b6001600160a01b0382163b1561473b57604051630a85bd0160e11b80825233600483015260006024830181905260448301849052608060648401526084830152906001600160a01b0384169063150b7a029060a4016020604051808303816000875af11580156146cd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906146f191906154b7565b6001600160e01b0319161461473b5760405162461bcd60e51b815260206004820152601060248201526f155394d0519157d49150d2541251539560821b6044820152606401610cf7565b5050565b6001600160a01b0382166147895760405162461bcd60e51b81526020600482015260116024820152701253959053125117d49150d25412515395607a1b6044820152606401610cf7565b6000818152600260205260409020546001600160a01b0316156147ee5760405162461bcd60e51b815260206004820152600e60248201527f414c52454144595f4d494e5445440000000000000000000000000000000000006044820152606401610cf7565b6001600160a01b038216600081815260036020908152604080832080546001019055848352600290915280822080546001600160a01b0319168417905551839291907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a45050565b50805460008255906000526020600020908101906148779190614947565b50565b828054828255906000526020600020906007016008900481019282156149195791602002820160005b838211156148e757835183826101000a81548163ffffffff021916908363ffffffff16021790555092602001926004016020816003010492830192600103026148a3565b80156149175782816101000a81549063ffffffff02191690556004016020816003010492830192600103026148e7565b505b50614925929150614977565b5090565b50805460008255906000526020600020908101906148779190614977565b5b8082111561492557805477ffffffffffffffffffffffffffffffffffffffffffffffff19168155600101614948565b5b808211156149255760008155600101614978565b6001600160e01b03198116811461487757600080fd5b6000602082840312156149b457600080fd5b81356149bf8161498c565b9392505050565b60005b838110156149e15781810151838201526020016149c9565b50506000910152565b60008151808452614a028160208601602086016149c6565b601f01601f19169290920160200192915050565b6020815260006149bf60208301846149ea565b600060208284031215614a3b57600080fd5b5035919050565b6001600160a01b038116811461487757600080fd5b60008060408385031215614a6a57600080fd5b8235614a7581614a42565b946020939093013593505050565b600060208284031215614a9557600080fd5b81356149bf81614a42565b6000604080830185845260208281860152818651808452606087019150828801935060005b81811015614af9578451805163ffffffff1684528401516001600160601b0316848401529383019391850191600101614ac5565b509098975050505050505050565b60008060408385031215614b1a57600080fd5b50508035926020909101359150565b600081518084526020808501945080840160005b83811015614b625781516001600160a01b031687529582019590820190600101614b3d565b509495945050505050565b828152604060208201526000614b866040830184614b29565b949350505050565b600080600060608486031215614ba357600080fd5b8335614bae81614a42565b92506020840135614bbe81614a42565b929592945050506040919091013590565b634e487b7160e01b600052602160045260246000fd5b60068110614c0357634e487b7160e01b600052602160045260246000fd5b9052565b6001600160601b03881681526001600160a01b03871660208201526040810186905263ffffffff85811660608301528481166080830152831660a082015260e08101614c5660c0830184614be5565b98975050505050505050565b634e487b7160e01b600052604160045260246000fd5b6040805190810167ffffffffffffffff81118282101715614c9b57614c9b614c62565b60405290565b604051601f8201601f1916810167ffffffffffffffff81118282101715614cca57614cca614c62565b604052919050565b600067ffffffffffffffff831115614cec57614cec614c62565b614cff601f8401601f1916602001614ca1565b9050828152838383011115614d1357600080fd5b828260208301376000602084830101529392505050565b600060208284031215614d3c57600080fd5b813567ffffffffffffffff811115614d5357600080fd5b8201601f81018413614d6457600080fd5b614b8684823560208401614cd2565b600067ffffffffffffffff821115614d8d57614d8d614c62565b5060051b60200190565b600082601f830112614da857600080fd5b81356020614dbd614db883614d73565b614ca1565b82815260059290921b84018101918181019086841115614ddc57600080fd5b8286015b84811015614e00578035614df381614a42565b8352918301918301614de0565b509695505050505050565b80356001600160601b03811681146115dc57600080fd5b600080600060608486031215614e3757600080fd5b833567ffffffffffffffff80821115614e4f57600080fd5b614e5b87838801614d97565b9450602091508186013581811115614e7257600080fd5b86019050601f81018713614e8557600080fd5b8035614e93614db882614d73565b81815260059190911b82018301908381019089831115614eb257600080fd5b928401925b82841015614ed757614ec884614e0b565b82529284019290840190614eb7565b96999698505050506040949094013593505050565b60008060408385031215614eff57600080fd5b8235614f0a81614a42565b915060208301358015158114614f1f57600080fd5b809150509250929050565b6000604082018483526020604081850152818551808452606086019150828701935060005b81811015614f6b57845183529383019391830191600101614f4f565b5090979650505050505050565b600080600080600060808688031215614f9057600080fd5b8535614f9b81614a42565b94506020860135614fab81614a42565b935060408601359250606086013567ffffffffffffffff80821115614fcf57600080fd5b818801915088601f830112614fe357600080fd5b813581811115614ff257600080fd5b89602082850101111561500457600080fd5b9699959850939650602001949392505050565b803563ffffffff811681146115dc57600080fd5b600082601f83011261503c57600080fd5b8135602061504c614db883614d73565b82815260059290921b8401810191818101908684111561506b57600080fd5b8286015b84811015614e005761508081615017565b835291830191830161506f565b600082601f83011261509e57600080fd5b813560206150ae614db883614d73565b82815260069290921b840181019181810190868411156150cd57600080fd5b8286015b84811015614e0057604081890312156150ea5760008081fd5b6150f2614c78565b6150fb82615017565b8152615108858301614e0b565b818601528352918301916040016150d1565b60008060008060008060c0878903121561513357600080fd5b863561513e81614a42565b955060208701359450604087013567ffffffffffffffff8082111561516257600080fd5b61516e8a838b0161502b565b9550606089013591508082111561518457600080fd5b5061519189828a0161508d565b9350506151a060808801615017565b915060a087013590509295509295509295565b600080600080608085870312156151c957600080fd5b84356151d481614a42565b935060208501359250604085013567ffffffffffffffff808211156151f857600080fd5b61520488838901614d97565b9350606087013591508082111561521a57600080fd5b506152278782880161502b565b91505092959194509250565b6000806040838503121561524657600080fd5b823561525181614a42565b91506020830135614f1f81614a42565b600081518084526020808501945080840160005b83811015614b6257815163ffffffff1687529582019590820190600101615275565b602081526001600160601b0382511660208201526001600160a01b03602083015116604082015260408201516060820152600060608301516152e1608084018263ffffffff169052565b50608083015163ffffffff811660a08401525060a083015163ffffffff811660c08401525060c083015161531860e0840182614be5565b5060e083015161010083810152614b86610120840182615261565b6000806000806080858703121561534957600080fd5b843561535481614a42565b935060208501359250604085013561536b81614a42565b9150606085013567ffffffffffffffff81111561538757600080fd5b8501601f8101871361539857600080fd5b61522787823560208401614cd2565b600080600080600060a086880312156153bf57600080fd5b85356153ca81614a42565b945060208601359350604086013567ffffffffffffffff808211156153ee57600080fd5b6153fa89838a0161502b565b9450606088013591508082111561541057600080fd5b5061541d8882890161508d565b92505061542c60808701615017565b90509295509295909350565b600181811c9082168061544c57607f821691505b60208210810361546c57634e487b7160e01b600052602260045260246000fd5b50919050565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b6000600182016154b0576154b0615488565b5060010190565b6000602082840312156154c957600080fd5b81516149bf8161498c565b80820180821115610be157610be1615488565b601f82111561142357600081815260208120601f850160051c8101602086101561550e5750805b601f850160051c820191505b8181101561552d5782815560010161551a565b505050505050565b815167ffffffffffffffff81111561554f5761554f614c62565b6155638161555d8454615438565b846154e7565b602080601f83116001811461559857600084156155805750858301515b600019600386901b1c1916600185901b17855561552d565b600085815260208120601f198616915b828110156155c7578886015182559484019460019091019084016155a8565b50858210156155e55787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6001600160601b0381811683821601908082111561561557615615615488565b5092915050565b6001600160601b0382811682821603908082111561561557615615615488565b63ffffffff82811682821603908082111561561557615615615488565b60006001600160a01b03808816835280871660208401525084604083015260806060830152826080830152828460a0840137600060a0848401015260a0601f19601f85011683010190509695505050505050565b60008086546156bb81615438565b600182811680156156d357600181146156e857615717565b60ff1984168752821515830287019450615717565b8a60005260208060002060005b8581101561570e5781548a8201529084019082016156f5565b50505082870194505b50505050855161572b818360208a016149c6565b019384525050602082015260400192915050565b600063ffffffff80831681810361575857615758615488565b6001019392505050565b6060815260006157756060830186614b29565b63ffffffff85166020840152828103604084015261579381856149ea565b9695505050505050565b6000602082840312156157af57600080fd5b81516149bf81614a42565b8082028115828204841417610be157610be1615488565b63ffffffff81811683821601908082111561561557615615615488565b63ffffffff8181168382160280821691908281146140b0576140b0615488565b634e487b7160e01b600052601260045260246000fd5b6000826158335761583361580e565b500690565b6000826158475761584761580e565b50049056fea2646970667358221220ee3dd136eb9c3aaae80969db0d981f4555af6520415662932908c79dee30e48b64736f6c63430008130033", + "linkReferences": {}, + "deployedLinkReferences": {} +} \ No newline at end of file diff --git a/packages/valory/contracts/service_registry/contract.py b/packages/valory/contracts/service_registry/contract.py index 6b7cfa9a3a..20e21888a5 100644 --- a/packages/valory/contracts/service_registry/contract.py +++ b/packages/valory/contracts/service_registry/contract.py @@ -20,35 +20,48 @@ """This module contains the class to connect to the Service Registry contract.""" import hashlib +import json import logging -from typing import Any, Dict, List, Optional, Set, Tuple, Union, cast +from pathlib import Path +from typing import Any, Dict, FrozenSet, List, Optional, Tuple, Union, cast from aea.common import JSONLike from aea.configurations.base import PublicId from aea.contracts.base import Contract -from aea_ledger_ethereum import EthereumApi, LedgerApi +from aea.crypto.base import LedgerApi +from web3.types import BlockData, EventData, TxReceipt +PUBLIC_ID = PublicId.from_str("valory/service_registry:0.1.0") +ETHEREUM_IDENTIFIER = "ethereum" +UNIT_HASH_PREFIX = "0x{metadata_hash}" EXPECTED_CONTRACT_ADDRESS_BY_CHAIN_ID = { 1: "0x48b6af7B12C71f09e2fC8aF4855De4Ff54e775cA", 5: "0x1cEe30D08943EB58EFF84DD1AB44a6ee6FEff63a", + 100: "0x9338b5153AE39BB89f50468E608eD9d764B755fD", + 137: "0xE3607b00E75f6405248323A9417ff6b39B244b50", 31337: "0x998abeb3E57409262aE5b751f60747921B33613E", } DEPLOYED_BYTECODE_MD5_HASH_BY_CHAIN_ID = { 1: "6f9fc7f3c2348801737120e6b5f8fa8e9670c65152c66d128ff4cddb465b4d705340c559e352f5e7f29bda3b84a8d36d4a9448b791cfe2d370e31c01276e0244", 5: "d4a860f21f17762c99d93359244b39a878dd5bac9ea6056c0ff29c7558d6653aa0d5962aa819fc9f05f237d068845125cfc37a7fd7761b11c29a709ad5c48157", - 31337: "d8084598f884509694ab1f244cbb8e7697d8db00c241710b89b2ec3037d2edd3b82d01f1f0ca6bd9b265b1184d9c563a6000c30958c2a7ae5a9c35e5ff2ba7de", + 100: "10e2cfb500481d6c5a3b6b90507e4ac04d8b0d88741cea5568306ed4115f24e8b9747055423da5fca05838d5ccefebf41fb47d2ba1fb45215b6b21c0a27823be", + 137: "10e2cfb500481d6c5a3b6b90507e4ac04d8b0d88741cea5568306ed4115f24e8b9747055423da5fca05838d5ccefebf41fb47d2ba1fb45215b6b21c0a27823be", + 31337: "41ab54d43fd4bdfdc929658a0dc9bedd970c7339eecafbefda9892ab54c02c396bceedaa3a84a0f4690bee03dc11195a3267a264de7859c420efbf4291f1fef0", } -UNIT_HASH_PREFIX = "0x{metadata_hash}" +L1_CHAINS = ( + 1, + 5, + 31337, +) +L2_BUILD_FILENAME = "ServiceRegistryL2.json" -PUBLIC_ID = PublicId.from_str("valory/service_registry:0.1.0") +ServiceInfo = Tuple[int, str, bytes, int, int, int, int, List[int]] _logger = logging.getLogger( f"aea.packages.{PUBLIC_ID.author}.contracts.{PUBLIC_ID.name}.contract" ) -ServiceInfo = Tuple[int, str, bytes, int, int, int, int, List[int]] - class ServiceRegistryContract(Contract): """The Service Registry contract.""" @@ -76,6 +89,37 @@ def get_state( """Get state.""" raise NotImplementedError # pragma: nocover + @staticmethod + def is_l1_chain(ledger_api: LedgerApi) -> bool: + """Check if we're interecting with an L1 chain""" + return ledger_api.api.eth.chain_id in L1_CHAINS + + @staticmethod + def load_l2_build() -> JSONLike: + """Load L2 ABI""" + path = Path(__file__).parent / "build" / L2_BUILD_FILENAME + return json.loads(path.read_text(encoding="utf-8")) + + @classmethod + def get_instance( + cls, + ledger_api: LedgerApi, + contract_address: Optional[str] = None, + ) -> Any: + """Get contract instance.""" + if ledger_api.identifier != ETHEREUM_IDENTIFIER: + return super().get_instance( + ledger_api=ledger_api, contract_address=contract_address + ) + if cls.is_l1_chain(ledger_api=ledger_api): + contract_interface = cls.contract_interface.get(ledger_api.identifier, {}) + else: + contract_interface = cls.load_l2_build() + instance = ledger_api.get_contract_instance( + contract_interface, contract_address + ) + return instance + @classmethod def verify_contract( cls, ledger_api: LedgerApi, contract_address: str @@ -88,7 +132,6 @@ def verify_contract( :return: the verified status """ verified = False - ledger_api = cast(EthereumApi, ledger_api) chain_id = ledger_api.api.eth.chain_id expected_address = EXPECTED_CONTRACT_ADDRESS_BY_CHAIN_ID[chain_id] if contract_address != expected_address: @@ -99,7 +142,7 @@ def verify_contract( deployed_bytecode = ledger_api.api.eth.get_code(contract_address).hex() sha512_hash = hashlib.sha512(deployed_bytecode.encode("utf-8")).hexdigest() verified = DEPLOYED_BYTECODE_MD5_HASH_BY_CHAIN_ID[chain_id] == sha512_hash - if not verified: + if not verified: # pragma: nocover _logger.error( f"CONTRACT NOT VERIFIED! Contract address: {contract_address}, chain_id: {chain_id}." ) @@ -154,7 +197,7 @@ def get_service_owner( """Retrieve the service owner.""" contract_instance = cls.get_instance(ledger_api, contract_address) service_owner = contract_instance.functions.ownerOf(service_id).call() - checksum_service_owner = ledger_api.api.toChecksumAddress(service_owner) + checksum_service_owner = ledger_api.api.to_checksum_address(service_owner) return dict( service_owner=checksum_service_owner, ) @@ -181,8 +224,7 @@ def get_token_uri( contract_address: str, token_id: int, ) -> str: - """Resolve token URI""" - + """Returns the latest metadata URI for a component.""" contract_interface = cls.get_instance( ledger_api=ledger_api, contract_address=contract_address, @@ -190,102 +232,171 @@ def get_token_uri( return contract_interface.functions.tokenURI(token_id).call() @classmethod - def filter_token_id_from_emitted_events( + def get_create_events( # pragma: nocover cls, ledger_api: LedgerApi, contract_address: str, + receipt: JSONLike, ) -> Optional[int]: """Returns `CreateUnit` event filter.""" - contract_interface = cls.get_instance( ledger_api=ledger_api, contract_address=contract_address, ) + return contract_interface.events.CreateService().process_receipt(receipt) - events = contract_interface.events.CreateService.createFilter( - fromBlock="latest" - ).get_all_entries() + @classmethod + def get_update_events( # pragma: nocover + cls, + ledger_api: LedgerApi, + contract_address: str, + receipt: JSONLike, + ) -> Optional[int]: + """Returns `CreateUnit` event filter.""" + contract_interface = cls.get_instance( + ledger_api=ledger_api, + contract_address=contract_address, + ) + return contract_interface.events.UpdateService().process_receipt(receipt) - for event in events: - event_args = event["args"] - if "serviceId" in event_args: - return cast(int, event_args["serviceId"]) + @classmethod + def get_update_hash_events( # pragma: nocover + cls, + ledger_api: LedgerApi, + contract_address: str, + receipt: JSONLike, + ) -> Optional[int]: + """Returns `CreateUnit` event filter.""" + contract_interface = cls.get_instance( + ledger_api=ledger_api, + contract_address=contract_address, + ) + return contract_interface.events.UpdateUnitHash().process_receipt(receipt) - return None + @classmethod + def get_events( # pragma: nocover + cls, + ledger_api: LedgerApi, + contract_address: str, + event: str, + receipt: JSONLike, + ) -> Dict: + """Process receipt for events.""" + contract_interface = cls.get_instance( + ledger_api=ledger_api, + contract_address=contract_address, + ) + Event = getattr(contract_interface.events, event, None) + if Event is None: + return {"events": []} + return {"events": Event().process_receipt(receipt)} @classmethod - def verify_service_has_been_activated( + def process_receipt( cls, ledger_api: LedgerApi, contract_address: str, - service_id: int, - ) -> bool: + event: str, + receipt: JSONLike, + ) -> JSONLike: """Checks for a successful service registration event in the latest block""" - contract_interface = cls.get_instance( ledger_api=ledger_api, contract_address=contract_address, ) - - events = contract_interface.events.ActivateRegistration.createFilter( - fromBlock="latest" - ).get_all_entries() - for event in events: - if event["args"]["serviceId"] == service_id: - return True - - return False + Event = getattr(contract_interface.events, event, None) + if Event is None: + return {"events": []} + return {"events": Event().process_receipt(receipt)} @classmethod - def verify_agent_instance_registration( + def get_slash_data( cls, ledger_api: LedgerApi, contract_address: str, + agent_instances: List[str], + amounts: List[int], service_id: int, - instance_check: Set[str], - ) -> Set[str]: - """Checks for the registered instances and filters out the instances that are registered from the given array""" + ) -> Dict[str, bytes]: + """Gets the encoded arguments for a slashing tx, which should only be called via the multisig.""" - contract_interface = cls.get_instance( + contract_instance = cls.get_instance( ledger_api=ledger_api, contract_address=contract_address, ) - events = contract_interface.events.RegisterInstance.createFilter( - fromBlock="latest" - ).get_all_entries() + slash_kwargs = dict( + agentInstances=agent_instances, + amounts=amounts, + serviceId=service_id, + ) + + data = contract_instance.encodeABI(fn_name="slash", kwargs=slash_kwargs) + return {"data": bytes.fromhex(data[2:])} + + @classmethod + def process_slash_receipt( + cls, + ledger_api: LedgerApi, + contract_address: str, + tx_hash: str, + ) -> Optional[JSONLike]: + """ + Process the slash receipt. + + :param ledger_api: the ledger apis. + :param contract_address: the contract address. + :param tx_hash: the hash of a slash tx to be processed. + :return: a dictionary with the timestamp of the slashing and the `OperatorSlashed` events. + """ + contract = cls.get_instance(ledger_api, contract_address) + receipt: TxReceipt = ledger_api.api.eth.get_transaction_receipt(tx_hash) + logs: List[EventData] = list( + contract.events.OperatorSlashed().process_receipt(receipt) + ) - successful = set() - for event in events: - event_args = event["args"] - if event_args["serviceId"] != service_id: - continue + if len(logs) == 0: + _logger.error(f"No `OperatorSlashed` event was emitted in tx {tx_hash}.") + return None - agent_instance = event_args["agentInstance"] - if agent_instance in instance_check: - successful.add(agent_instance) + block: BlockData = ledger_api.api.eth.get_block(receipt["blockNumber"]) - return successful + return { + "slash_timestamp": block["timestamp"], + "events": [log["args"] for log in logs], + } @classmethod - def verify_service_has_been_deployed( + def _get_operator( cls, ledger_api: LedgerApi, contract_address: str, - service_id: int, - ) -> bool: - """Checks for a successful service registration event in the latest block""" + agent_instance: str, + ) -> str: + """Retrieve an operator given its agent instance.""" - contract_interface = cls.get_instance( - ledger_api=ledger_api, - contract_address=contract_address, - ) + contract_instance = cls.get_instance(ledger_api, contract_address) + map_fn = contract_instance.functions.mapAgentInstanceOperators + return map_fn(agent_instance).call() + + @classmethod + def get_operators_mapping( + cls, + ledger_api: LedgerApi, + contract_address: str, + agent_instances: FrozenSet[str], + ) -> Dict[str, str]: + """ + Retrieve a mapping of the given agent instances to their operators. - events = contract_interface.events.DeployService.createFilter( - fromBlock="latest" - ).get_all_entries() - for event in events: - if event["args"]["serviceId"] == service_id: - return True + Please keep in mind that this method performs a call for each agent instance. - return False + :param ledger_api: the ledger api. + :param contract_address: the contract address. + :param agent_instances: the agent instances to be mapped. + :return: a mapping of the given agent instances to their operators. + """ + return { + agent: cls._get_operator(ledger_api, contract_address, agent) + for agent in agent_instances + } diff --git a/packages/valory/contracts/service_registry/contract.yaml b/packages/valory/contracts/service_registry/contract.yaml index d11ecee1ec..0b85f9d42f 100644 --- a/packages/valory/contracts/service_registry/contract.yaml +++ b/packages/valory/contracts/service_registry/contract.yaml @@ -8,17 +8,19 @@ aea_version: '>=1.0.0, <2.0.0' fingerprint: __init__.py: bafybeidey4syohls5hxmso6qsp5p4uhtzle5txv2mlbym6ktjzknich6oa build/ServiceRegistry.json: bafybeia4qi2vstrutejzrxfpbb6eift7va5cjs7bparaal2fafiiczuiyy - contract.py: bafybeibhaifwdnam4mkrsnw3dwo2ust3iuk4azuothajpyie6cltr326uu + build/ServiceRegistryL2.json: bafybeic2jylwfod4nmdtbs4izyxyi246pd3f35aoqyahnmyrvzn7j3sv4e + contract.py: bafybeihaixq3vettolpxspv6nog6vltqwshug7ltbpvb2i3rw2mps5o2li tests/__init__.py: bafybeicl2oklx774jomlt6wwwegfdzrxh6iazjxwcyc7h4gepjljkpl4ji - tests/test_contract.py: bafybeicx6kbyez4myel3sombygi74x45esscwnioxowowshn3wfmykd7vy + tests/test_contract.py: bafybeicj535veqf35zb3ycu5iqjvqgj4a2kdmogmx5ba7fiolt5chah42a fingerprint_ignore_patterns: [] contracts: [] class_name: ServiceRegistryContract contract_interface_paths: ethereum: build/ServiceRegistry.json - ethereum_hwi: build/ServiceRegistry.json dependencies: open-aea-ledger-ethereum: - version: ==1.32.0 + version: ==1.43.0.post2 open-aea-test-autonomy: - version: ==0.10.2 + version: ==0.13.9.post1 + web3: + version: <7,>=6.0.0 diff --git a/packages/valory/contracts/service_registry/tests/test_contract.py b/packages/valory/contracts/service_registry/tests/test_contract.py index 8ca26d82a9..a54e84143a 100644 --- a/packages/valory/contracts/service_registry/tests/test_contract.py +++ b/packages/valory/contracts/service_registry/tests/test_contract.py @@ -19,7 +19,7 @@ """Tests for valory/service_registry contract.""" from pathlib import Path -from typing import Any, List, Optional, Set +from typing import Any from unittest import mock import pytest @@ -40,6 +40,14 @@ VALID_SERVICE_ID = 1 INVALID_SERVICE_ID = 0 CHAIN_ID = 31337 +AGENT_INSTANCES = [ + "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", + "0x70997970C51812dc3A010C7d01b50e0d17dc79C8", + "0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC", + "0x90F79bf6EB2c4f870365E785982E1f101E93b906", +] +OPERATOR = "0xBcd4042DE499D14e55001CcbB24a551F3b954096" +OPERATORS_MAPPING = dict.fromkeys(AGENT_INSTANCES, OPERATOR) def event_filter_patch(event: str, return_value: Any) -> mock._patch: @@ -51,7 +59,7 @@ def event_filter_patch(event: str, return_value: Any) -> mock._patch: events=mock.MagicMock( **{ event: mock.MagicMock( - createFilter=lambda **_: mock.MagicMock( + create_filter=lambda **_: mock.MagicMock( get_all_entries=lambda *_: return_value ) ) @@ -112,12 +120,7 @@ def test_get_agent_instances(self) -> None: return_value = { "numAgentInstances": 4, - "agentInstances": [ - "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", - "0x70997970C51812dc3A010C7d01b50e0d17dc79C8", - "0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC", - "0x90F79bf6EB2c4f870365E785982E1f101E93b906", - ], + "agentInstances": AGENT_INSTANCES, } assert self.contract_address is not None @@ -132,7 +135,7 @@ def test_get_agent_instances(self) -> None: def test_get_service_owner(self) -> None: """Test service owner retrieval.""" - service_owner = "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" + service_owner = AGENT_INSTANCES[0] assert self.contract_address is not None actual = self.contract.get_service_owner( @@ -177,7 +180,7 @@ def test_get_service_information(self) -> None: ) assert security_deposit == 10000000000000000 - assert multisig_address == "0xD8dE647170163a981bb3Fdb2063583eAcF7D55AC" + assert multisig_address == "0x77b783e911F4398D75908Cc60C7138Bd1eFe35Fd" assert ipfs_hash_for_config == b"UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU" assert threshold == 3 assert max_number_of_agent_instances == 4 @@ -185,121 +188,52 @@ def test_get_service_information(self) -> None: assert service_state == 4 assert list_of_cannonical_agents == [1] - @pytest.mark.parametrize( - ("return_value", "assert_value"), - ( - ([], None), - ( - [ - { - "args": { - "serviceId": 1, - } - } - ], - 1, - ), - ), - ) - def test_filter_token_id_from_emitted_events( - self, return_value: List, assert_value: Optional[int] - ) -> None: - """Test `filter_token_id_from_emitted_events` method""" - - with event_filter_patch(event="CreateService", return_value=return_value): - token_id = self.contract.filter_token_id_from_emitted_events( - ledger_api=self.ledger_api, - contract_address=self.contract_address, - ) - - if assert_value is None: - assert token_id is None - else: - assert token_id == 1 - - @pytest.mark.parametrize( - ("return_value", "assert_value"), - ( - ([], False), - ( - [ - { - "args": { - "serviceId": 0, - } - } - ], - True, - ), - ), - ) - def test_verify_service_has_been_activated( - self, return_value: List, assert_value: bool - ) -> None: - """Test `verify_service_has_been_activated` method.""" - - with event_filter_patch( - event="ActivateRegistration", return_value=return_value - ): - success = self.contract.verify_service_has_been_activated( - ledger_api=self.ledger_api, - contract_address=self.contract_address, - service_id=0, - ) - - assert success is assert_value - - @pytest.mark.parametrize( - ("return_value", "assert_value"), - ( - ([], set()), - ( - [{"args": {"serviceId": 0, "agentInstance": "0x"}}], - {"0x"}, - ), - ), - ) - def test_verify_agent_instance_registration( - self, return_value: List, assert_value: Set[str] - ) -> None: - """Test `verify_agent_instance_registration` method.""" - - with event_filter_patch(event="RegisterInstance", return_value=return_value): - successful = self.contract.verify_agent_instance_registration( - ledger_api=self.ledger_api, - contract_address=self.contract_address, - service_id=0, - instance_check={"0x"}, - ) - - assert successful == assert_value + def test_get_slash_data(self) -> None: + """Test the `get_slash_data`.""" + result = self.contract.get_slash_data( + self.ledger_api, + self.contract_address, + AGENT_INSTANCES, + [0, 0, 0, 1], + service_id=1, + ) - @pytest.mark.parametrize( - ("return_value", "assert_value"), - ( - ([], False), - ( - [ - { - "args": { - "serviceId": 0, - } - } - ], - True, - ), - ), - ) - def test_verify_service_has_been_deployed( - self, return_value: List, assert_value: bool - ) -> None: - """Test `verify_service_has_been_deployed` method.""" - - with event_filter_patch(event="DeployService", return_value=return_value): - success = self.contract.verify_service_has_been_deployed( - ledger_api=self.ledger_api, - contract_address=self.contract_address, - service_id=0, + assert result.get("data", b"") == ( + b"s\xb8\xb6\xa2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + b"\x00\x00\x00\x00\x00\x00\x00\x00`\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00" + b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04" + b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf3\x9f\xd6\xe5\x1a\xad\x88\xf6\xf4\xcej\xb8\x82ry\xcf" + b'\xff\xb9"f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00p\x99yp\xc5\x18\x12\xdc:\x01\x0c}\x01\xb5\x0e\r' + b"\x17\xdcy\xc8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 None: + """Test `get_operator` method.""" + for agent_instance, expected_operator in OPERATORS_MAPPING.items(): + actual_operator = ( + self.contract._get_operator( # pylint: disable=protected-access + self.ledger_api, + self.contract_address, + agent_instance, + ) ) + assert actual_operator == expected_operator - assert success is assert_value + def test_get_operators_mapping(self) -> None: + """Test `get_operator` method.""" + actual_mapping = self.contract.get_operators_mapping( + self.ledger_api, + self.contract_address, + frozenset(OPERATORS_MAPPING.keys()), + ) + assert actual_mapping == OPERATORS_MAPPING diff --git a/packages/valory/contracts/service_registry_token_utility/__init__.py b/packages/valory/contracts/service_registry_token_utility/__init__.py new file mode 100644 index 0000000000..9e8332df28 --- /dev/null +++ b/packages/valory/contracts/service_registry_token_utility/__init__.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# ------------------------------------------------------------------------------ +# +# Copyright 2023 valory +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# ------------------------------------------------------------------------------ + +"""This module contains the support resources for the scaffold contract.""" diff --git a/packages/valory/contracts/service_registry_token_utility/build/ServiceRegistryTokenUtility.json b/packages/valory/contracts/service_registry_token_utility/build/ServiceRegistryTokenUtility.json new file mode 100644 index 0000000000..723802496b --- /dev/null +++ b/packages/valory/contracts/service_registry_token_utility/build/ServiceRegistryTokenUtility.json @@ -0,0 +1,926 @@ +{ + "_format": "hh-sol-artifact-1", + "contractName": "ServiceRegistryTokenUtility", + "sourceName": "contracts/ServiceRegistryTokenUtility.sol", + "abi": [ + { + "inputs": [ + { + "internalType": "address", + "name": "_serviceRegistry", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "operator", + "type": "address" + } + ], + "name": "AgentInstanceRegistered", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "serviceId", + "type": "uint256" + } + ], + "name": "AgentInstancesSlotsFilled", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "agentId", + "type": "uint256" + } + ], + "name": "AgentNotFound", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "agentId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "serviceId", + "type": "uint256" + } + ], + "name": "AgentNotInService", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "componentId", + "type": "uint256" + } + ], + "name": "ComponentNotFound", + "type": "error" + }, + { + "inputs": [], + "name": "HashExists", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "sent", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "expected", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "serviceId", + "type": "uint256" + } + ], + "name": "IncorrectAgentBondingValue", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "sent", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "expected", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "serviceId", + "type": "uint256" + } + ], + "name": "IncorrectRegistrationDepositValue", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "internalType": "address", + "name": "manager", + "type": "address" + } + ], + "name": "ManagerOnly", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "provided", + "type": "address" + }, + { + "internalType": "address", + "name": "expected", + "type": "address" + }, + { + "internalType": "uint256", + "name": "serviceId", + "type": "uint256" + } + ], + "name": "OnlyOwnServiceMultisig", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "operator", + "type": "address" + }, + { + "internalType": "uint256", + "name": "serviceId", + "type": "uint256" + } + ], + "name": "OperatorHasNoInstances", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "provided", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "max", + "type": "uint256" + } + ], + "name": "Overflow", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "internalType": "address", + "name": "owner", + "type": "address" + } + ], + "name": "OwnerOnly", + "type": "error" + }, + { + "inputs": [], + "name": "Paused", + "type": "error" + }, + { + "inputs": [], + "name": "ReentrancyGuard", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "serviceId", + "type": "uint256" + } + ], + "name": "ServiceMustBeInactive", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "token", + "type": "address" + } + ], + "name": "TokenRejected", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "TransferFailed", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "multisig", + "type": "address" + } + ], + "name": "UnauthorizedMultisig", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "agentId", + "type": "uint256" + } + ], + "name": "WrongAgentId", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "numValues1", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "numValues2", + "type": "uint256" + } + ], + "name": "WrongArrayLength", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "serviceId", + "type": "uint256" + } + ], + "name": "WrongOperator", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "state", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "serviceId", + "type": "uint256" + } + ], + "name": "WrongServiceState", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "currentThreshold", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "minThreshold", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "maxThreshold", + "type": "uint256" + } + ], + "name": "WrongThreshold", + "type": "error" + }, + { + "inputs": [], + "name": "ZeroAddress", + "type": "error" + }, + { + "inputs": [], + "name": "ZeroValue", + "type": "error" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "drainer", + "type": "address" + } + ], + "name": "DrainerUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "manager", + "type": "address" + } + ], + "name": "ManagerUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "address", + "name": "operator", + "type": "address" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "serviceId", + "type": "uint256" + } + ], + "name": "OperatorTokenSlashed", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + } + ], + "name": "OwnerUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "TokenDeposit", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "drainer", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "TokenDrain", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "TokenRefund", + "type": "event" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "serviceId", + "type": "uint256" + } + ], + "name": "activateRegistrationTokenDeposit", + "outputs": [ + { + "internalType": "bool", + "name": "isTokenSecured", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newDrainer", + "type": "address" + } + ], + "name": "changeDrainer", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newManager", + "type": "address" + } + ], + "name": "changeManager", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "changeOwner", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "serviceId", + "type": "uint256" + }, + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "uint32[]", + "name": "agentIds", + "type": "uint32[]" + }, + { + "internalType": "uint256[]", + "name": "bonds", + "type": "uint256[]" + } + ], + "name": "createWithToken", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "token", + "type": "address" + } + ], + "name": "drain", + "outputs": [ + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "drainer", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "serviceId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "agentId", + "type": "uint256" + } + ], + "name": "getAgentBond", + "outputs": [ + { + "internalType": "uint256", + "name": "bond", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "operator", + "type": "address" + }, + { + "internalType": "uint256", + "name": "serviceId", + "type": "uint256" + } + ], + "name": "getOperatorBalance", + "outputs": [ + { + "internalType": "uint256", + "name": "balance", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "serviceId", + "type": "uint256" + } + ], + "name": "isTokenSecuredService", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "manager", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "mapOperatorAndServiceIdOperatorBalances", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "mapServiceAndAgentIdAgentBond", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "mapServiceIdTokenDeposit", + "outputs": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "uint96", + "name": "securityDeposit", + "type": "uint96" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "mapSlashedFunds", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "owner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "operator", + "type": "address" + }, + { + "internalType": "uint256", + "name": "serviceId", + "type": "uint256" + }, + { + "internalType": "uint32[]", + "name": "agentIds", + "type": "uint32[]" + } + ], + "name": "registerAgentsTokenDeposit", + "outputs": [ + { + "internalType": "bool", + "name": "isTokenSecured", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "serviceId", + "type": "uint256" + } + ], + "name": "resetServiceToken", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "serviceRegistry", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address[]", + "name": "agentInstances", + "type": "address[]" + }, + { + "internalType": "uint256[]", + "name": "amounts", + "type": "uint256[]" + }, + { + "internalType": "uint256", + "name": "serviceId", + "type": "uint256" + } + ], + "name": "slash", + "outputs": [ + { + "internalType": "bool", + "name": "success", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "serviceId", + "type": "uint256" + } + ], + "name": "terminateTokenRefund", + "outputs": [ + { + "internalType": "uint256", + "name": "securityRefund", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "operator", + "type": "address" + }, + { + "internalType": "uint256", + "name": "serviceId", + "type": "uint256" + } + ], + "name": "unbondTokenRefund", + "outputs": [ + { + "internalType": "uint256", + "name": "refund", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + } + ], + "bytecode": "0x60a0604052600160035534801561001557600080fd5b5060405162001f3a38038062001f3a83398101604081905261003691610080565b6001600160a01b03811661005d5760405163d92e233d60e01b815260040160405180910390fd5b6001600160a01b0316608052600080546001600160a01b031916331790556100b0565b60006020828403121561009257600080fd5b81516001600160a01b03811681146100a957600080fd5b9392505050565b608051611e52620000e8600039600081816103be015281816105c1015281816106bd015281816108470152610b630152611e526000f3fe608060405234801561001057600080fd5b50600436106101825760003560e01c806375c1f934116100d8578063b0f4c2481161008c578063dc4f8bc511610066578063dc4f8bc514610400578063e3ce9a8414610413578063ece531321461042657600080fd5b8063b0f4c248146103a6578063cbcf252a146103b9578063cbd413a5146103e057600080fd5b80638da5cb5b116100bd5780638da5cb5b1461036d578063a3fbbaae14610380578063a6f9dae11461039357600080fd5b806375c1f934146103165780638a2bd86f1461033e57600080fd5b806346d7836d1161013a578063542db44911610114578063542db449146102dd57806357838e85146102f05780635f3662581461030357600080fd5b806346d7836d14610264578063481c6a751461029f5780635419bb8c146102ca57600080fd5b806325e1afc31161016b57806325e1afc3146101cf5780633cebfa4f146101e2578063421448541461024457600080fd5b806310c6aa191461018757806313f824d81461019c575b600080fd5b61019a610195366004611956565b610439565b005b6101bc6101aa36600461197a565b60056020526000908152604090205481565b6040519081526020015b60405180910390f35b6101bc6101dd36600461197a565b6104fc565b61021d6101f036600461197a565b6004602052600090815260409020546001600160a01b03811690600160a01b90046001600160601b031682565b604080516001600160a01b0390931683526001600160601b039091166020830152016101c6565b6101bc61025236600461197a565b60066020526000908152604090205481565b61028f61027236600461197a565b6000908152600460205260409020546001600160a01b0316151590565b60405190151581526020016101c6565b6001546102b2906001600160a01b031681565b6040516001600160a01b0390911681526020016101c6565b61028f6102d8366004611a69565b6106b6565b61028f6102eb36600461197a565b610a88565b6002546102b2906001600160a01b031681565b61019a61031136600461197a565b610e0e565b6101bc610324366004611b34565b602090811b90911760009081526005909152604090205490565b6101bc61034c366004611b56565b60a01b6001600160a01b039091161760009081526006602052604090205490565b6000546102b2906001600160a01b031681565b61019a61038e366004611956565b610e5f565b61019a6103a1366004611956565b610f1d565b6101bc6103b4366004611b56565b610fd9565b6102b27f000000000000000000000000000000000000000000000000000000000000000081565b6101bc6103ee366004611956565b60076020526000908152604090205481565b61028f61040e366004611bf8565b6110ff565b61019a610421366004611c51565b611464565b6101bc610434366004611956565b611708565b6000546001600160a01b0316331461047e5760005460405163521eb56d60e11b81523360048201526001600160a01b0390911660248201526044015b60405180910390fd5b6001600160a01b0381166104a55760405163d92e233d60e01b815260040160405180910390fd5b6002805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b0383169081179091556040517f8d1e8547016120917daad7f81c42b48f7fee379badc48f1889f0f43bb619472590600090a250565b600060016003541115610522576040516345f5ce8b60e11b815260040160405180910390fd5b60026003556001546001600160a01b031633146105675760015460405163312d21ff60e11b81523360048201526001600160a01b039091166024820152604401610475565b6000828152600460209081526040918290208251808401909352546001600160a01b038116808452600160a01b9091046001600160601b03169183019190915280156106aa5781602001516001600160601b0316925060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316636352211e866040518263ffffffff1660e01b815260040161060d91815260200190565b602060405180830381865afa15801561062a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061064e9190611cd1565b905061065b828286611831565b816001600160a01b0316816001600160a01b03167fb5ea3bd24bc48df54cdc99f11e448ab16503a3e16f46c363202f5fff4891acba866040516106a091815260200190565b60405180910390a3505b50506001600355919050565b60008060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316634236aff8856040518263ffffffff1660e01b815260040161070991815260200190565b60e060405180830381865afa158015610726573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061074a9190611cee565b9650505050509250508060ff1660041461078357604051633c053f9d60e21b815260ff8216600482015260248101859052604401610475565b8551158061079357508451865114155b156107be57855185516040516308151c1160e41b815260048101929092526024820152604401610475565b336001600160a01b038316146107ff576040516379f91cd360e01b81523360048201526001600160a01b038316602482015260448101859052606401610475565b6000848152600460205260409020546001600160a01b0316806108355760405163d92e233d60e01b815260040160405180910390fd5b86516000805b82811015610a395760007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316634eb780da8c848151811061088657610886611d92565b60200260200101516040518263ffffffff1660e01b81526004016108b991906001600160a01b0391909116815260200190565b602060405180830381865afa1580156108d6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108fa9190611cd1565b60a08a901b6001600160a01b0382161760008181526006602052604081205492935090919081900361092e57505050610a29565b808c858151811061094157610941611d92565b602002602001015110610963576109588186611dbe565b9450600090506109b2565b8b848151811061097557610975611d92565b6020026020010151856109889190611dbe565b94508b848151811061099c5761099c611d92565b6020026020010151816109af9190611dd7565b90505b60008281526006602052604090208190558b518b906001600160a01b038516907fd79658b314eb967321e5e6a82ab39f6f7ffc567d38c6feee527761aca406a597908f9088908110610a0657610a06611d92565b6020026020010151604051610a1d91815260200190565b60405180910390a35050505b610a3281611dea565b905061083b565b506001600160a01b038316600090815260076020526040902054610a5d9082611dbe565b6001600160a01b03909316600090815260076020526040902092909255506001979650505050505050565b600060016003541115610aae576040516345f5ce8b60e11b815260040160405180910390fd5b60026003556001546001600160a01b03163314610af35760015460405163312d21ff60e11b81523360048201526001600160a01b039091166024820152604401610475565b6000828152600460209081526040918290208251808401909352546001600160a01b038116808452600160a01b9091046001600160601b03169183019190915280156106aa5760208201516040516331a9108f60e11b8152600481018690526001600160601b03909116906000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690636352211e90602401602060405180830381865afa158015610bb2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bd69190611cd1565b604051636eb1769f60e11b81526001600160a01b03808316600483015230602483015291925060009185169063dd62ed3e90604401602060405180830381865afa158015610c28573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c4c9190611e03565b905082811015610c8057604051631c30abbb60e31b8152600481018290526024810184905260448101889052606401610475565b6040516370a0823160e01b8152306004820152600196506000906001600160a01b038616906370a0823190602401602060405180830381865afa158015610ccb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cef9190611e03565b9050610cfd858430876118b4565b6040516370a0823160e01b81523060048201526000906001600160a01b038716906370a0823190602401602060405180830381865afa158015610d44573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d689190611e03565b905080821180610d81575084610d7e8383611dd7565b14155b15610db057604051631c30abbb60e31b81526000600482015260248101869052604481018a9052606401610475565b856001600160a01b0316846001600160a01b03167f98c09d9949722bae4bd0d988d4050091c3ae7ec6d51d3c6bbfe4233593944e9e87604051610df591815260200190565b60405180910390a3505050505050506001600355919050565b6001546001600160a01b03163314610e4e5760015460405163312d21ff60e11b81523360048201526001600160a01b039091166024820152604401610475565b600090815260046020526040812055565b6000546001600160a01b03163314610e9f5760005460405163521eb56d60e11b81523360048201526001600160a01b039091166024820152604401610475565b6001600160a01b038116610ec65760405163d92e233d60e01b815260040160405180910390fd5b6001805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b0383169081179091556040517f2c1c11af44aa5608f1dca38c00275c30ea091e02417d36e70e9a1538689c433d90600090a250565b6000546001600160a01b03163314610f5d5760005460405163521eb56d60e11b81523360048201526001600160a01b039091166024820152604401610475565b6001600160a01b038116610f845760405163d92e233d60e01b815260040160405180910390fd5b6000805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b038316908117825560405190917f4ffd725fc4a22075e9ec71c59edf9c38cdeb588a91b24fc5b61388c5be41282b91a250565b600060016003541115610fff576040516345f5ce8b60e11b815260040160405180910390fd5b60026003556001546001600160a01b031633146110445760015460405163312d21ff60e11b81523360048201526001600160a01b039091166024820152604401610475565b6000828152600460205260409020546001600160a01b031680156110f35760a083901b6001600160a01b03851617600081815260066020526040902054925082156110f1576000818152600660205260408120556110a3828685611831565b816001600160a01b0316856001600160a01b03167fb5ea3bd24bc48df54cdc99f11e448ab16503a3e16f46c363202f5fff4891acba856040516110e891815260200190565b60405180910390a35b505b50600160035592915050565b600060016003541115611125576040516345f5ce8b60e11b815260040160405180910390fd5b60026003556001546001600160a01b0316331461116a5760015460405163312d21ff60e11b81523360048201526001600160a01b039091166024820152604401610475565b6000838152600460205260409020546001600160a01b031680156114575782516000805b828110156111f757600087905060208783815181106111af576111af611d92565b60209081029190910181015163ffffffff1690911b91909117600081815260059092526040909120546111e28185611dbe565b93505050806111f090611dea565b905061118e565b50604051636eb1769f60e11b81526001600160a01b0388811660048301523060248301526000919085169063dd62ed3e90604401602060405180830381865afa158015611248573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061126c9190611e03565b9050818110156112a057604051637ebbcab960e11b8152600481018290526024810183905260448101889052606401610475565b60a087901b6001600160a01b03891617600081815260066020526040812080548592906112ce908490611dbe565b90915550506040516370a0823160e01b8152306004820152600196506000906001600160a01b038716906370a0823190602401602060405180830381865afa15801561131e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113429190611e03565b9050611350868b30876118b4565b6040516370a0823160e01b81523060048201526000906001600160a01b038816906370a0823190602401602060405180830381865afa158015611397573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113bb9190611e03565b9050808211806113d45750846113d18383611dd7565b14155b1561140357604051637ebbcab960e11b81526000600482015260248101869052604481018b9052606401610475565b866001600160a01b03168b6001600160a01b03167f98c09d9949722bae4bd0d988d4050091c3ae7ec6d51d3c6bbfe4233593944e9e8760405161144891815260200190565b60405180910390a35050505050505b5060016003559392505050565b6001546001600160a01b031633146114a45760015460405163312d21ff60e11b81523360048201526001600160a01b039091166024820152604401610475565b60408051600060248083018290528351808403909101815260449092019092526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff166370a0823160e01b1790527f70a08231b98ef4ca268c9cc3f6b4590e4bfec28280db06bb5d45e689f2a360be91906001600160a01b0386163b1561153557600080825160208401895afa91505b8161155e5760405163e77376f360e01b81526001600160a01b0387166004820152602401610475565b6000805b86518110156116b45785818151811061157d5761157d611d92565b6020026020010151600003156116a4576001600160601b0380168682815181106115a9576115a9611d92565b60200260200101511115611606578581815181106115c9576115c9611d92565b60200260200101516001600160601b03604051637ae5968560e01b81526004016104759291909182526001600160601b0316602082015260400190565b6000899050602088838151811061161f5761161f611d92565b602002602001015163ffffffff16901b8117905086828151811061164557611645611d92565b602002602001015160056000838152602001908152602001600020819055508287838151811061167757611677611d92565b602002602001015111156116a25786828151811061169757611697611d92565b602002602001015192505b505b6116ad81611dea565b9050611562565b506040805180820182526001600160a01b0398891681526001600160601b03928316602080830191825260009b8c52600490529190992098519051909116600160a01b029616959095179095555050505050565b60006001600354111561172e576040516345f5ce8b60e11b815260040160405180910390fd5b60026003556000546001600160a01b031633146117735760005460405163521eb56d60e11b81523360048201526001600160a01b039091166024820152604401610475565b6002546001600160a01b031661179c5760405163d92e233d60e01b815260040160405180910390fd5b506001600160a01b0381166000908152600760205260409020548015611827576001600160a01b038083166000908152600760205260408120556002546117e69184911683611831565b6040518181526001600160a01b0383169033907feb64d3e0fe21df59e0edd78e9749e4bc9f3cf593a842d487fe40f29ef45fdad69060200160405180910390a35b6001600355919050565b600060405163a9059cbb60e01b6000528360045282602452602060006044600080895af13d15601f3d11600160005114161716915060006060528060405250806118ae5760405163cd3f165960e01b81526001600160a01b0380861660048301523060248301528416604482015260648101839052608401610475565b50505050565b60006040516323b872dd60e01b6000528460045283602452826044526020600060646000808a5af13d15601f3d11600160005114161716915060006060528060405250806119375760405163cd3f165960e01b81526001600160a01b03808716600483015280861660248301528416604482015260648101839052608401610475565b5050505050565b6001600160a01b038116811461195357600080fd5b50565b60006020828403121561196857600080fd5b81356119738161193e565b9392505050565b60006020828403121561198c57600080fd5b5035919050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff811182821017156119d2576119d2611993565b604052919050565b600067ffffffffffffffff8211156119f4576119f4611993565b5060051b60200190565b600082601f830112611a0f57600080fd5b81356020611a24611a1f836119da565b6119a9565b82815260059290921b84018101918181019086841115611a4357600080fd5b8286015b84811015611a5e5780358352918301918301611a47565b509695505050505050565b600080600060608486031215611a7e57600080fd5b833567ffffffffffffffff80821115611a9657600080fd5b818601915086601f830112611aaa57600080fd5b81356020611aba611a1f836119da565b82815260059290921b8401810191818101908a841115611ad957600080fd5b948201945b83861015611b00578535611af18161193e565b82529482019490820190611ade565b97505087013592505080821115611b1657600080fd5b50611b23868287016119fe565b925050604084013590509250925092565b60008060408385031215611b4757600080fd5b50508035926020909101359150565b60008060408385031215611b6957600080fd5b8235611b748161193e565b946020939093013593505050565b63ffffffff8116811461195357600080fd5b600082601f830112611ba557600080fd5b81356020611bb5611a1f836119da565b82815260059290921b84018101918181019086841115611bd457600080fd5b8286015b84811015611a5e578035611beb81611b82565b8352918301918301611bd8565b600080600060608486031215611c0d57600080fd5b8335611c188161193e565b925060208401359150604084013567ffffffffffffffff811115611c3b57600080fd5b611c4786828701611b94565b9150509250925092565b60008060008060808587031215611c6757600080fd5b843593506020850135611c798161193e565b9250604085013567ffffffffffffffff80821115611c9657600080fd5b611ca288838901611b94565b93506060870135915080821115611cb857600080fd5b50611cc5878288016119fe565b91505092959194509250565b600060208284031215611ce357600080fd5b81516119738161193e565b600080600080600080600060e0888a031215611d0957600080fd5b87516001600160601b0381168114611d2057600080fd5b6020890151909750611d318161193e565b604089015160608a01519197509550611d4981611b82565b6080890151909450611d5a81611b82565b60a0890151909350611d6b81611b82565b60c089015190925060ff81168114611d8257600080fd5b8091505092959891949750929550565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b80820180821115611dd157611dd1611da8565b92915050565b81810381811115611dd157611dd1611da8565b600060018201611dfc57611dfc611da8565b5060010190565b600060208284031215611e1557600080fd5b505191905056fea2646970667358221220e38aad42f76663645ad01adefd7b54c3c3a128669aadd1939110bdc298d0532264736f6c63430008130033", + "deployedBytecode": "0x608060405234801561001057600080fd5b50600436106101825760003560e01c806375c1f934116100d8578063b0f4c2481161008c578063dc4f8bc511610066578063dc4f8bc514610400578063e3ce9a8414610413578063ece531321461042657600080fd5b8063b0f4c248146103a6578063cbcf252a146103b9578063cbd413a5146103e057600080fd5b80638da5cb5b116100bd5780638da5cb5b1461036d578063a3fbbaae14610380578063a6f9dae11461039357600080fd5b806375c1f934146103165780638a2bd86f1461033e57600080fd5b806346d7836d1161013a578063542db44911610114578063542db449146102dd57806357838e85146102f05780635f3662581461030357600080fd5b806346d7836d14610264578063481c6a751461029f5780635419bb8c146102ca57600080fd5b806325e1afc31161016b57806325e1afc3146101cf5780633cebfa4f146101e2578063421448541461024457600080fd5b806310c6aa191461018757806313f824d81461019c575b600080fd5b61019a610195366004611956565b610439565b005b6101bc6101aa36600461197a565b60056020526000908152604090205481565b6040519081526020015b60405180910390f35b6101bc6101dd36600461197a565b6104fc565b61021d6101f036600461197a565b6004602052600090815260409020546001600160a01b03811690600160a01b90046001600160601b031682565b604080516001600160a01b0390931683526001600160601b039091166020830152016101c6565b6101bc61025236600461197a565b60066020526000908152604090205481565b61028f61027236600461197a565b6000908152600460205260409020546001600160a01b0316151590565b60405190151581526020016101c6565b6001546102b2906001600160a01b031681565b6040516001600160a01b0390911681526020016101c6565b61028f6102d8366004611a69565b6106b6565b61028f6102eb36600461197a565b610a88565b6002546102b2906001600160a01b031681565b61019a61031136600461197a565b610e0e565b6101bc610324366004611b34565b602090811b90911760009081526005909152604090205490565b6101bc61034c366004611b56565b60a01b6001600160a01b039091161760009081526006602052604090205490565b6000546102b2906001600160a01b031681565b61019a61038e366004611956565b610e5f565b61019a6103a1366004611956565b610f1d565b6101bc6103b4366004611b56565b610fd9565b6102b27f000000000000000000000000000000000000000000000000000000000000000081565b6101bc6103ee366004611956565b60076020526000908152604090205481565b61028f61040e366004611bf8565b6110ff565b61019a610421366004611c51565b611464565b6101bc610434366004611956565b611708565b6000546001600160a01b0316331461047e5760005460405163521eb56d60e11b81523360048201526001600160a01b0390911660248201526044015b60405180910390fd5b6001600160a01b0381166104a55760405163d92e233d60e01b815260040160405180910390fd5b6002805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b0383169081179091556040517f8d1e8547016120917daad7f81c42b48f7fee379badc48f1889f0f43bb619472590600090a250565b600060016003541115610522576040516345f5ce8b60e11b815260040160405180910390fd5b60026003556001546001600160a01b031633146105675760015460405163312d21ff60e11b81523360048201526001600160a01b039091166024820152604401610475565b6000828152600460209081526040918290208251808401909352546001600160a01b038116808452600160a01b9091046001600160601b03169183019190915280156106aa5781602001516001600160601b0316925060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316636352211e866040518263ffffffff1660e01b815260040161060d91815260200190565b602060405180830381865afa15801561062a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061064e9190611cd1565b905061065b828286611831565b816001600160a01b0316816001600160a01b03167fb5ea3bd24bc48df54cdc99f11e448ab16503a3e16f46c363202f5fff4891acba866040516106a091815260200190565b60405180910390a3505b50506001600355919050565b60008060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316634236aff8856040518263ffffffff1660e01b815260040161070991815260200190565b60e060405180830381865afa158015610726573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061074a9190611cee565b9650505050509250508060ff1660041461078357604051633c053f9d60e21b815260ff8216600482015260248101859052604401610475565b8551158061079357508451865114155b156107be57855185516040516308151c1160e41b815260048101929092526024820152604401610475565b336001600160a01b038316146107ff576040516379f91cd360e01b81523360048201526001600160a01b038316602482015260448101859052606401610475565b6000848152600460205260409020546001600160a01b0316806108355760405163d92e233d60e01b815260040160405180910390fd5b86516000805b82811015610a395760007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316634eb780da8c848151811061088657610886611d92565b60200260200101516040518263ffffffff1660e01b81526004016108b991906001600160a01b0391909116815260200190565b602060405180830381865afa1580156108d6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108fa9190611cd1565b60a08a901b6001600160a01b0382161760008181526006602052604081205492935090919081900361092e57505050610a29565b808c858151811061094157610941611d92565b602002602001015110610963576109588186611dbe565b9450600090506109b2565b8b848151811061097557610975611d92565b6020026020010151856109889190611dbe565b94508b848151811061099c5761099c611d92565b6020026020010151816109af9190611dd7565b90505b60008281526006602052604090208190558b518b906001600160a01b038516907fd79658b314eb967321e5e6a82ab39f6f7ffc567d38c6feee527761aca406a597908f9088908110610a0657610a06611d92565b6020026020010151604051610a1d91815260200190565b60405180910390a35050505b610a3281611dea565b905061083b565b506001600160a01b038316600090815260076020526040902054610a5d9082611dbe565b6001600160a01b03909316600090815260076020526040902092909255506001979650505050505050565b600060016003541115610aae576040516345f5ce8b60e11b815260040160405180910390fd5b60026003556001546001600160a01b03163314610af35760015460405163312d21ff60e11b81523360048201526001600160a01b039091166024820152604401610475565b6000828152600460209081526040918290208251808401909352546001600160a01b038116808452600160a01b9091046001600160601b03169183019190915280156106aa5760208201516040516331a9108f60e11b8152600481018690526001600160601b03909116906000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690636352211e90602401602060405180830381865afa158015610bb2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bd69190611cd1565b604051636eb1769f60e11b81526001600160a01b03808316600483015230602483015291925060009185169063dd62ed3e90604401602060405180830381865afa158015610c28573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c4c9190611e03565b905082811015610c8057604051631c30abbb60e31b8152600481018290526024810184905260448101889052606401610475565b6040516370a0823160e01b8152306004820152600196506000906001600160a01b038616906370a0823190602401602060405180830381865afa158015610ccb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cef9190611e03565b9050610cfd858430876118b4565b6040516370a0823160e01b81523060048201526000906001600160a01b038716906370a0823190602401602060405180830381865afa158015610d44573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d689190611e03565b905080821180610d81575084610d7e8383611dd7565b14155b15610db057604051631c30abbb60e31b81526000600482015260248101869052604481018a9052606401610475565b856001600160a01b0316846001600160a01b03167f98c09d9949722bae4bd0d988d4050091c3ae7ec6d51d3c6bbfe4233593944e9e87604051610df591815260200190565b60405180910390a3505050505050506001600355919050565b6001546001600160a01b03163314610e4e5760015460405163312d21ff60e11b81523360048201526001600160a01b039091166024820152604401610475565b600090815260046020526040812055565b6000546001600160a01b03163314610e9f5760005460405163521eb56d60e11b81523360048201526001600160a01b039091166024820152604401610475565b6001600160a01b038116610ec65760405163d92e233d60e01b815260040160405180910390fd5b6001805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b0383169081179091556040517f2c1c11af44aa5608f1dca38c00275c30ea091e02417d36e70e9a1538689c433d90600090a250565b6000546001600160a01b03163314610f5d5760005460405163521eb56d60e11b81523360048201526001600160a01b039091166024820152604401610475565b6001600160a01b038116610f845760405163d92e233d60e01b815260040160405180910390fd5b6000805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b038316908117825560405190917f4ffd725fc4a22075e9ec71c59edf9c38cdeb588a91b24fc5b61388c5be41282b91a250565b600060016003541115610fff576040516345f5ce8b60e11b815260040160405180910390fd5b60026003556001546001600160a01b031633146110445760015460405163312d21ff60e11b81523360048201526001600160a01b039091166024820152604401610475565b6000828152600460205260409020546001600160a01b031680156110f35760a083901b6001600160a01b03851617600081815260066020526040902054925082156110f1576000818152600660205260408120556110a3828685611831565b816001600160a01b0316856001600160a01b03167fb5ea3bd24bc48df54cdc99f11e448ab16503a3e16f46c363202f5fff4891acba856040516110e891815260200190565b60405180910390a35b505b50600160035592915050565b600060016003541115611125576040516345f5ce8b60e11b815260040160405180910390fd5b60026003556001546001600160a01b0316331461116a5760015460405163312d21ff60e11b81523360048201526001600160a01b039091166024820152604401610475565b6000838152600460205260409020546001600160a01b031680156114575782516000805b828110156111f757600087905060208783815181106111af576111af611d92565b60209081029190910181015163ffffffff1690911b91909117600081815260059092526040909120546111e28185611dbe565b93505050806111f090611dea565b905061118e565b50604051636eb1769f60e11b81526001600160a01b0388811660048301523060248301526000919085169063dd62ed3e90604401602060405180830381865afa158015611248573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061126c9190611e03565b9050818110156112a057604051637ebbcab960e11b8152600481018290526024810183905260448101889052606401610475565b60a087901b6001600160a01b03891617600081815260066020526040812080548592906112ce908490611dbe565b90915550506040516370a0823160e01b8152306004820152600196506000906001600160a01b038716906370a0823190602401602060405180830381865afa15801561131e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113429190611e03565b9050611350868b30876118b4565b6040516370a0823160e01b81523060048201526000906001600160a01b038816906370a0823190602401602060405180830381865afa158015611397573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113bb9190611e03565b9050808211806113d45750846113d18383611dd7565b14155b1561140357604051637ebbcab960e11b81526000600482015260248101869052604481018b9052606401610475565b866001600160a01b03168b6001600160a01b03167f98c09d9949722bae4bd0d988d4050091c3ae7ec6d51d3c6bbfe4233593944e9e8760405161144891815260200190565b60405180910390a35050505050505b5060016003559392505050565b6001546001600160a01b031633146114a45760015460405163312d21ff60e11b81523360048201526001600160a01b039091166024820152604401610475565b60408051600060248083018290528351808403909101815260449092019092526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff166370a0823160e01b1790527f70a08231b98ef4ca268c9cc3f6b4590e4bfec28280db06bb5d45e689f2a360be91906001600160a01b0386163b1561153557600080825160208401895afa91505b8161155e5760405163e77376f360e01b81526001600160a01b0387166004820152602401610475565b6000805b86518110156116b45785818151811061157d5761157d611d92565b6020026020010151600003156116a4576001600160601b0380168682815181106115a9576115a9611d92565b60200260200101511115611606578581815181106115c9576115c9611d92565b60200260200101516001600160601b03604051637ae5968560e01b81526004016104759291909182526001600160601b0316602082015260400190565b6000899050602088838151811061161f5761161f611d92565b602002602001015163ffffffff16901b8117905086828151811061164557611645611d92565b602002602001015160056000838152602001908152602001600020819055508287838151811061167757611677611d92565b602002602001015111156116a25786828151811061169757611697611d92565b602002602001015192505b505b6116ad81611dea565b9050611562565b506040805180820182526001600160a01b0398891681526001600160601b03928316602080830191825260009b8c52600490529190992098519051909116600160a01b029616959095179095555050505050565b60006001600354111561172e576040516345f5ce8b60e11b815260040160405180910390fd5b60026003556000546001600160a01b031633146117735760005460405163521eb56d60e11b81523360048201526001600160a01b039091166024820152604401610475565b6002546001600160a01b031661179c5760405163d92e233d60e01b815260040160405180910390fd5b506001600160a01b0381166000908152600760205260409020548015611827576001600160a01b038083166000908152600760205260408120556002546117e69184911683611831565b6040518181526001600160a01b0383169033907feb64d3e0fe21df59e0edd78e9749e4bc9f3cf593a842d487fe40f29ef45fdad69060200160405180910390a35b6001600355919050565b600060405163a9059cbb60e01b6000528360045282602452602060006044600080895af13d15601f3d11600160005114161716915060006060528060405250806118ae5760405163cd3f165960e01b81526001600160a01b0380861660048301523060248301528416604482015260648101839052608401610475565b50505050565b60006040516323b872dd60e01b6000528460045283602452826044526020600060646000808a5af13d15601f3d11600160005114161716915060006060528060405250806119375760405163cd3f165960e01b81526001600160a01b03808716600483015280861660248301528416604482015260648101839052608401610475565b5050505050565b6001600160a01b038116811461195357600080fd5b50565b60006020828403121561196857600080fd5b81356119738161193e565b9392505050565b60006020828403121561198c57600080fd5b5035919050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff811182821017156119d2576119d2611993565b604052919050565b600067ffffffffffffffff8211156119f4576119f4611993565b5060051b60200190565b600082601f830112611a0f57600080fd5b81356020611a24611a1f836119da565b6119a9565b82815260059290921b84018101918181019086841115611a4357600080fd5b8286015b84811015611a5e5780358352918301918301611a47565b509695505050505050565b600080600060608486031215611a7e57600080fd5b833567ffffffffffffffff80821115611a9657600080fd5b818601915086601f830112611aaa57600080fd5b81356020611aba611a1f836119da565b82815260059290921b8401810191818101908a841115611ad957600080fd5b948201945b83861015611b00578535611af18161193e565b82529482019490820190611ade565b97505087013592505080821115611b1657600080fd5b50611b23868287016119fe565b925050604084013590509250925092565b60008060408385031215611b4757600080fd5b50508035926020909101359150565b60008060408385031215611b6957600080fd5b8235611b748161193e565b946020939093013593505050565b63ffffffff8116811461195357600080fd5b600082601f830112611ba557600080fd5b81356020611bb5611a1f836119da565b82815260059290921b84018101918181019086841115611bd457600080fd5b8286015b84811015611a5e578035611beb81611b82565b8352918301918301611bd8565b600080600060608486031215611c0d57600080fd5b8335611c188161193e565b925060208401359150604084013567ffffffffffffffff811115611c3b57600080fd5b611c4786828701611b94565b9150509250925092565b60008060008060808587031215611c6757600080fd5b843593506020850135611c798161193e565b9250604085013567ffffffffffffffff80821115611c9657600080fd5b611ca288838901611b94565b93506060870135915080821115611cb857600080fd5b50611cc5878288016119fe565b91505092959194509250565b600060208284031215611ce357600080fd5b81516119738161193e565b600080600080600080600060e0888a031215611d0957600080fd5b87516001600160601b0381168114611d2057600080fd5b6020890151909750611d318161193e565b604089015160608a01519197509550611d4981611b82565b6080890151909450611d5a81611b82565b60a0890151909350611d6b81611b82565b60c089015190925060ff81168114611d8257600080fd5b8091505092959891949750929550565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b80820180821115611dd157611dd1611da8565b92915050565b81810381811115611dd157611dd1611da8565b600060018201611dfc57611dfc611da8565b5060010190565b600060208284031215611e1557600080fd5b505191905056fea2646970667358221220e38aad42f76663645ad01adefd7b54c3c3a128669aadd1939110bdc298d0532264736f6c63430008130033", + "linkReferences": {}, + "deployedLinkReferences": {} +} \ No newline at end of file diff --git a/packages/valory/contracts/service_registry_token_utility/contract.py b/packages/valory/contracts/service_registry_token_utility/contract.py new file mode 100644 index 0000000000..f3a77596a1 --- /dev/null +++ b/packages/valory/contracts/service_registry_token_utility/contract.py @@ -0,0 +1,117 @@ +# -*- coding: utf-8 -*- +# ------------------------------------------------------------------------------ +# +# Copyright 2023 valory +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# ------------------------------------------------------------------------------ + +"""This module contains the scaffold contract definition.""" + +from typing import Any + +from aea.common import JSONLike +from aea.configurations.base import PublicId +from aea.contracts.base import Contract +from aea.crypto.base import LedgerApi + + +class ServiceRegistryTokenUtilityContract(Contract): + """The scaffold contract class for a smart contract.""" + + contract_id = PublicId.from_str("valory/service_registry_token_utility:0.1.0") + + @classmethod + def get_raw_transaction( + cls, ledger_api: LedgerApi, contract_address: str, **kwargs: Any + ) -> JSONLike: + """ + Handler method for the 'GET_RAW_TRANSACTION' requests. + + Implement this method in the sub class if you want + to handle the contract requests manually. + + :param ledger_api: the ledger apis. + :param contract_address: the contract address. + :param kwargs: the keyword arguments. + :return: the tx # noqa: DAR202 + """ + raise NotImplementedError + + @classmethod + def get_raw_message( + cls, ledger_api: LedgerApi, contract_address: str, **kwargs: Any + ) -> bytes: + """ + Handler method for the 'GET_RAW_MESSAGE' requests. + + Implement this method in the sub class if you want + to handle the contract requests manually. + + :param ledger_api: the ledger apis. + :param contract_address: the contract address. + :param kwargs: the keyword arguments. + :return: the tx # noqa: DAR202 + """ + raise NotImplementedError + + @classmethod + def get_state( + cls, ledger_api: LedgerApi, contract_address: str, **kwargs: Any + ) -> JSONLike: + """ + Handler method for the 'GET_STATE' requests. + + Implement this method in the sub class if you want + to handle the contract requests manually. + + :param ledger_api: the ledger apis. + :param contract_address: the contract address. + :param kwargs: the keyword arguments. + :return: the tx # noqa: DAR202 + """ + raise NotImplementedError + + @classmethod + def is_token_secured_service( + cls, + ledger_api: LedgerApi, + contract_address: str, + service_id: int, + ) -> JSONLike: + """Check if a service is secured service.""" + instance = cls.get_instance( + ledger_api=ledger_api, + contract_address=contract_address, + ) + return dict( + is_token_secured_service=instance.functions.isTokenSecuredService( + service_id + ).call() + ) + + @classmethod + def get_agent_bond( + cls, + ledger_api: LedgerApi, + contract_address: str, + service_id: int, + agent_id: int, + ) -> JSONLike: + """Check if a service is secured service.""" + instance = cls.get_instance( + ledger_api=ledger_api, + contract_address=contract_address, + ) + return dict(bond=instance.functions.getAgentBond(service_id, agent_id).call()) diff --git a/packages/valory/contracts/service_registry_token_utility/contract.yaml b/packages/valory/contracts/service_registry_token_utility/contract.yaml new file mode 100644 index 0000000000..abe8f0f575 --- /dev/null +++ b/packages/valory/contracts/service_registry_token_utility/contract.yaml @@ -0,0 +1,17 @@ +name: service_registry_token_utility +author: valory +version: 0.1.0 +type: contract +description: The scaffold contract scaffolds a contract to be implemented by the developer. +license: Apache-2.0 +aea_version: '>=1.0.0, <2.0.0' +fingerprint: + __init__.py: bafybeieeus2bbbexmthy4pnsdtgen4flxzk3ao5ekjbocvmrkhhszffbgu + build/ServiceRegistryTokenUtility.json: bafybeifdugnfcq45yqu3b555ivsaxmuu6u7vwjbxavxgo3drsmo6572gju + contract.py: bafybeib4tg5lfiamw7ejgj472eobdkkouaddqkkcgbuj4f2edydnhbbvgi +fingerprint_ignore_patterns: [] +class_name: ServiceRegistryTokenUtilityContract +contract_interface_paths: + ethereum: build/ServiceRegistryTokenUtility.json +dependencies: {} +contracts: [] diff --git a/packages/valory/protocols/abci/__init__.py b/packages/valory/protocols/abci/__init__.py index 8e3ffb4e19..bb475bd7cf 100644 --- a/packages/valory/protocols/abci/__init__.py +++ b/packages/valory/protocols/abci/__init__.py @@ -20,7 +20,7 @@ """ This module contains the support resources for the abci protocol. -It was created with protocol buffer compiler version `libprotoc 3.19.4` and aea protocol generator version `1.0.0`. +It was created with protocol buffer compiler version `libprotoc 24.3` and aea protocol generator version `1.0.0`. """ from packages.valory.protocols.abci.message import AbciMessage diff --git a/packages/valory/protocols/abci/abci_pb2.py b/packages/valory/protocols/abci/abci_pb2.py index 725f7cc2ac..b1454d4349 100644 --- a/packages/valory/protocols/abci/abci_pb2.py +++ b/packages/valory/protocols/abci/abci_pb2.py @@ -4,9 +4,8 @@ """Generated protocol buffer code.""" from google.protobuf import descriptor as _descriptor from google.protobuf import descriptor_pool as _descriptor_pool -from google.protobuf import message as _message -from google.protobuf import reflection as _reflection from google.protobuf import symbol_database as _symbol_database +from google.protobuf.internal import builder as _builder # @@protoc_insertion_point(imports) @@ -18,905 +17,161 @@ b'\n\nabci.proto\x12\x16\x61\x65\x61.valory.abci.v0_1_0"\x86P\n\x0b\x41\x62\x63iMessage\x12G\n\x05\x64ummy\x18\x05 \x01(\x0b\x32\x36.aea.valory.abci.v0_1_0.AbciMessage.Dummy_PerformativeH\x00\x12u\n\x1crequest_apply_snapshot_chunk\x18\x06 \x01(\x0b\x32M.aea.valory.abci.v0_1_0.AbciMessage.Request_Apply_Snapshot_Chunk_PerformativeH\x00\x12\x63\n\x13request_begin_block\x18\x07 \x01(\x0b\x32\x44.aea.valory.abci.v0_1_0.AbciMessage.Request_Begin_Block_PerformativeH\x00\x12]\n\x10request_check_tx\x18\x08 \x01(\x0b\x32\x41.aea.valory.abci.v0_1_0.AbciMessage.Request_Check_Tx_PerformativeH\x00\x12Y\n\x0erequest_commit\x18\t \x01(\x0b\x32?.aea.valory.abci.v0_1_0.AbciMessage.Request_Commit_PerformativeH\x00\x12\x61\n\x12request_deliver_tx\x18\n \x01(\x0b\x32\x43.aea.valory.abci.v0_1_0.AbciMessage.Request_Deliver_Tx_PerformativeH\x00\x12U\n\x0crequest_echo\x18\x0b \x01(\x0b\x32=.aea.valory.abci.v0_1_0.AbciMessage.Request_Echo_PerformativeH\x00\x12_\n\x11request_end_block\x18\x0c \x01(\x0b\x32\x42.aea.valory.abci.v0_1_0.AbciMessage.Request_End_Block_PerformativeH\x00\x12W\n\rrequest_flush\x18\r \x01(\x0b\x32>.aea.valory.abci.v0_1_0.AbciMessage.Request_Flush_PerformativeH\x00\x12U\n\x0crequest_info\x18\x0e \x01(\x0b\x32=.aea.valory.abci.v0_1_0.AbciMessage.Request_Info_PerformativeH\x00\x12\x61\n\x12request_init_chain\x18\x0f \x01(\x0b\x32\x43.aea.valory.abci.v0_1_0.AbciMessage.Request_Init_Chain_PerformativeH\x00\x12i\n\x16request_list_snapshots\x18\x10 \x01(\x0b\x32G.aea.valory.abci.v0_1_0.AbciMessage.Request_List_Snapshots_PerformativeH\x00\x12s\n\x1brequest_load_snapshot_chunk\x18\x11 \x01(\x0b\x32L.aea.valory.abci.v0_1_0.AbciMessage.Request_Load_Snapshot_Chunk_PerformativeH\x00\x12i\n\x16request_offer_snapshot\x18\x12 \x01(\x0b\x32G.aea.valory.abci.v0_1_0.AbciMessage.Request_Offer_Snapshot_PerformativeH\x00\x12W\n\rrequest_query\x18\x13 \x01(\x0b\x32>.aea.valory.abci.v0_1_0.AbciMessage.Request_Query_PerformativeH\x00\x12\x61\n\x12request_set_option\x18\x14 \x01(\x0b\x32\x43.aea.valory.abci.v0_1_0.AbciMessage.Request_Set_Option_PerformativeH\x00\x12w\n\x1dresponse_apply_snapshot_chunk\x18\x15 \x01(\x0b\x32N.aea.valory.abci.v0_1_0.AbciMessage.Response_Apply_Snapshot_Chunk_PerformativeH\x00\x12\x65\n\x14response_begin_block\x18\x16 \x01(\x0b\x32\x45.aea.valory.abci.v0_1_0.AbciMessage.Response_Begin_Block_PerformativeH\x00\x12_\n\x11response_check_tx\x18\x17 \x01(\x0b\x32\x42.aea.valory.abci.v0_1_0.AbciMessage.Response_Check_Tx_PerformativeH\x00\x12[\n\x0fresponse_commit\x18\x18 \x01(\x0b\x32@.aea.valory.abci.v0_1_0.AbciMessage.Response_Commit_PerformativeH\x00\x12\x63\n\x13response_deliver_tx\x18\x19 \x01(\x0b\x32\x44.aea.valory.abci.v0_1_0.AbciMessage.Response_Deliver_Tx_PerformativeH\x00\x12W\n\rresponse_echo\x18\x1a \x01(\x0b\x32>.aea.valory.abci.v0_1_0.AbciMessage.Response_Echo_PerformativeH\x00\x12\x61\n\x12response_end_block\x18\x1b \x01(\x0b\x32\x43.aea.valory.abci.v0_1_0.AbciMessage.Response_End_Block_PerformativeH\x00\x12\x61\n\x12response_exception\x18\x1c \x01(\x0b\x32\x43.aea.valory.abci.v0_1_0.AbciMessage.Response_Exception_PerformativeH\x00\x12Y\n\x0eresponse_flush\x18\x1d \x01(\x0b\x32?.aea.valory.abci.v0_1_0.AbciMessage.Response_Flush_PerformativeH\x00\x12W\n\rresponse_info\x18\x1e \x01(\x0b\x32>.aea.valory.abci.v0_1_0.AbciMessage.Response_Info_PerformativeH\x00\x12\x63\n\x13response_init_chain\x18\x1f \x01(\x0b\x32\x44.aea.valory.abci.v0_1_0.AbciMessage.Response_Init_Chain_PerformativeH\x00\x12k\n\x17response_list_snapshots\x18 \x01(\x0b\x32H.aea.valory.abci.v0_1_0.AbciMessage.Response_List_Snapshots_PerformativeH\x00\x12u\n\x1cresponse_load_snapshot_chunk\x18! \x01(\x0b\x32M.aea.valory.abci.v0_1_0.AbciMessage.Response_Load_Snapshot_Chunk_PerformativeH\x00\x12k\n\x17response_offer_snapshot\x18" \x01(\x0b\x32H.aea.valory.abci.v0_1_0.AbciMessage.Response_Offer_Snapshot_PerformativeH\x00\x12Y\n\x0eresponse_query\x18# \x01(\x0b\x32?.aea.valory.abci.v0_1_0.AbciMessage.Response_Query_PerformativeH\x00\x12\x63\n\x13response_set_option\x18$ \x01(\x0b\x32\x44.aea.valory.abci.v0_1_0.AbciMessage.Response_Set_Option_PerformativeH\x00\x1a\x7f\n\x0b\x43heckTxType\x12J\n\x04type\x18\x01 \x01(\x0e\x32<.aea.valory.abci.v0_1_0.AbciMessage.CheckTxType._CheckTxType"$\n\x0c_CheckTxType\x12\x07\n\x03NEW\x10\x00\x12\x0b\n\x07RECHECK\x10\x01\x1a\xac\x05\n\x0f\x43onsensusParams\x12N\n\x05\x62lock\x18\x01 \x01(\x0b\x32?.aea.valory.abci.v0_1_0.AbciMessage.ConsensusParams.BlockParams\x12T\n\x08\x65vidence\x18\x02 \x01(\x0b\x32\x42.aea.valory.abci.v0_1_0.AbciMessage.ConsensusParams.EvidenceParams\x12V\n\tvalidator\x18\x03 \x01(\x0b\x32\x43.aea.valory.abci.v0_1_0.AbciMessage.ConsensusParams.ValidatorParams\x12R\n\x07version\x18\x04 \x01(\x0b\x32\x41.aea.valory.abci.v0_1_0.AbciMessage.ConsensusParams.VersionParams\x1a*\n\x08\x44uration\x12\x0f\n\x07seconds\x18\x01 \x01(\x03\x12\r\n\x05nanos\x18\x02 \x01(\x05\x1a\x31\n\x0b\x42lockParams\x12\x11\n\tmax_bytes\x18\x01 \x01(\x03\x12\x0f\n\x07max_gas\x18\x02 \x01(\x03\x1a\x97\x01\n\x0e\x45videnceParams\x12\x1a\n\x12max_age_num_blocks\x18\x01 \x01(\x03\x12V\n\x10max_age_duration\x18\x02 \x01(\x0b\x32<.aea.valory.abci.v0_1_0.AbciMessage.ConsensusParams.Duration\x12\x11\n\tmax_bytes\x18\x03 \x01(\x03\x1a(\n\x0fValidatorParams\x12\x15\n\rpub_key_types\x18\x01 \x03(\t\x1a$\n\rVersionParams\x12\x13\n\x0b\x61pp_version\x18\x01 \x01(\x04\x1a\xed\x01\n\x06\x45vents\x12@\n\x06\x65vents\x18\x01 \x03(\x0b\x32\x30.aea.valory.abci.v0_1_0.AbciMessage.Events.Event\x1a;\n\x0e\x45ventAttribute\x12\x0b\n\x03key\x18\x01 \x01(\x0c\x12\r\n\x05value\x18\x02 \x01(\x0c\x12\r\n\x05index\x18\x03 \x01(\x08\x1a\x64\n\x05\x45vent\x12\x0c\n\x04type\x18\x01 \x01(\t\x12M\n\nattributes\x18\x02 \x03(\x0b\x32\x39.aea.valory.abci.v0_1_0.AbciMessage.Events.EventAttribute\x1a\xc5\x03\n\tEvidences\x12T\n\x14\x62yzantine_validators\x18\x01 \x03(\x0b\x32\x36.aea.valory.abci.v0_1_0.AbciMessage.Evidences.Evidence\x1a\xe1\x02\n\x08\x45vidence\x12Q\n\x04type\x18\x01 \x01(\x0e\x32\x43.aea.valory.abci.v0_1_0.AbciMessage.Evidences.Evidence.EvidenceType\x12O\n\tvalidator\x18\x02 \x01(\x0b\x32<.aea.valory.abci.v0_1_0.AbciMessage.LastCommitInfo.Validator\x12\x0e\n\x06height\x18\x03 \x01(\x03\x12;\n\x04time\x18\x04 \x01(\x0b\x32-.aea.valory.abci.v0_1_0.AbciMessage.Timestamp\x12\x1a\n\x12total_voting_power\x18\x05 \x01(\x03"H\n\x0c\x45videnceType\x12\x0b\n\x07UNKNOWN\x10\x00\x12\x12\n\x0e\x44UPLICATE_VOTE\x10\x01\x12\x17\n\x13LIGHT_CLIENT_ATTACK\x10\x02\x1a\xa4\x05\n\x06Header\x12L\n\x07version\x18\x01 \x01(\x0b\x32;.aea.valory.abci.v0_1_0.AbciMessage.Header.ConsensusVersion\x12\x10\n\x08\x63hain_id\x18\x02 \x01(\t\x12\x0e\n\x06height\x18\x03 \x01(\x03\x12;\n\x04time\x18\x04 \x01(\x0b\x32-.aea.valory.abci.v0_1_0.AbciMessage.Timestamp\x12I\n\rlast_block_id\x18\x05 \x01(\x0b\x32\x32.aea.valory.abci.v0_1_0.AbciMessage.Header.BlockID\x12\x18\n\x10last_commit_hash\x18\x06 \x01(\x0c\x12\x11\n\tdata_hash\x18\x07 \x01(\x0c\x12\x17\n\x0fvalidators_hash\x18\x08 \x01(\x0c\x12\x1c\n\x14next_validators_hash\x18\t \x01(\x0c\x12\x16\n\x0e\x63onsensus_hash\x18\n \x01(\x0c\x12\x10\n\x08\x61pp_hash\x18\x0b \x01(\x0c\x12\x19\n\x11last_results_hash\x18\x0c \x01(\x0c\x12\x15\n\revidence_hash\x18\r \x01(\x0c\x12\x18\n\x10proposer_address\x18\x0e \x01(\x0c\x1a.\n\x10\x43onsensusVersion\x12\r\n\x05\x62lock\x18\x01 \x01(\x04\x12\x0b\n\x03\x61pp\x18\x02 \x01(\x04\x1aj\n\x07\x42lockID\x12\x0c\n\x04hash\x18\x01 \x01(\x0c\x12Q\n\x0fpart_set_header\x18\x02 \x01(\x0b\x32\x38.aea.valory.abci.v0_1_0.AbciMessage.Header.PartSetHeader\x1a,\n\rPartSetHeader\x12\r\n\x05total\x18\x01 \x01(\r\x12\x0c\n\x04hash\x18\x02 \x01(\x0c\x1a\x90\x02\n\x0eLastCommitInfo\x12\r\n\x05round\x18\x01 \x01(\x05\x12J\n\x05votes\x18\x02 \x03(\x0b\x32;.aea.valory.abci.v0_1_0.AbciMessage.LastCommitInfo.VoteInfo\x1a+\n\tValidator\x12\x0f\n\x07\x61\x64\x64ress\x18\x01 \x01(\x0c\x12\r\n\x05power\x18\x03 \x01(\x03\x1av\n\x08VoteInfo\x12O\n\tvalidator\x18\x01 \x01(\x0b\x32<.aea.valory.abci.v0_1_0.AbciMessage.LastCommitInfo.Validator\x12\x19\n\x11signed_last_block\x18\x02 \x01(\x08\x1a\x81\x01\n\x08ProofOps\x12\x41\n\x03ops\x18\x01 \x03(\x0b\x32\x34.aea.valory.abci.v0_1_0.AbciMessage.ProofOps.ProofOp\x1a\x32\n\x07ProofOp\x12\x0c\n\x04type\x18\x01 \x01(\t\x12\x0b\n\x03key\x18\x02 \x01(\x0c\x12\x0c\n\x04\x64\x61ta\x18\x03 \x01(\x0c\x1a\xb8\x01\n\x06Result\x12J\n\x0bresult_type\x18\x01 \x01(\x0e\x32\x35.aea.valory.abci.v0_1_0.AbciMessage.Result.ResultType"b\n\nResultType\x12\x0b\n\x07UNKNOWN\x10\x00\x12\n\n\x06\x41\x43\x43\x45PT\x10\x01\x12\t\n\x05\x41\x42ORT\x10\x02\x12\n\n\x06REJECT\x10\x03\x12\x11\n\rREJECT_FORMAT\x10\x04\x12\x11\n\rREJECT_SENDER\x10\x05\x1aL\n\tSnapShots\x12?\n\tsnapshots\x18\x01 \x03(\x0b\x32,.aea.valory.abci.v0_1_0.AbciMessage.Snapshot\x1aZ\n\x08Snapshot\x12\x0e\n\x06height\x18\x01 \x01(\x04\x12\x0e\n\x06\x66ormat\x18\x02 \x01(\r\x12\x0e\n\x06\x63hunks\x18\x03 \x01(\r\x12\x0c\n\x04hash\x18\x04 \x01(\x0c\x12\x10\n\x08metadata\x18\x05 \x01(\x0c\x1a+\n\tTimestamp\x12\x0f\n\x07seconds\x18\x01 \x01(\x03\x12\r\n\x05nanos\x18\x02 \x01(\x05\x1a\x9b\x02\n\x10ValidatorUpdates\x12X\n\nvalidators\x18\x01 \x03(\x0b\x32\x44.aea.valory.abci.v0_1_0.AbciMessage.ValidatorUpdates.ValidatorUpdate\x1a:\n\tPublicKey\x12\x11\n\x07\x65\x64\x32\x35\x35\x31\x39\x18\x01 \x01(\x0cH\x00\x12\x13\n\tsecp256k1\x18\x02 \x01(\x0cH\x00\x42\x05\n\x03sum\x1aq\n\x0fValidatorUpdate\x12O\n\x07pub_key\x18\x01 \x01(\x0b\x32>.aea.valory.abci.v0_1_0.AbciMessage.ValidatorUpdates.PublicKey\x12\r\n\x05power\x18\x02 \x01(\x03\x1a,\n\x19Request_Echo_Performative\x12\x0f\n\x07message\x18\x01 \x01(\t\x1a\x1c\n\x1aRequest_Flush_Performative\x1aX\n\x19Request_Info_Performative\x12\x0f\n\x07version\x18\x01 \x01(\t\x12\x15\n\rblock_version\x18\x02 \x01(\x05\x12\x13\n\x0bp2p_version\x18\x03 \x01(\x05\x1aK\n\x1fRequest_Set_Option_Performative\x12\x12\n\noption_key\x18\x01 \x01(\t\x12\x14\n\x0coption_value\x18\x02 \x01(\t\x1a\xdb\x02\n\x1fRequest_Init_Chain_Performative\x12;\n\x04time\x18\x01 \x01(\x0b\x32-.aea.valory.abci.v0_1_0.AbciMessage.Timestamp\x12\x10\n\x08\x63hain_id\x18\x02 \x01(\t\x12M\n\x10\x63onsensus_params\x18\x03 \x01(\x0b\x32\x33.aea.valory.abci.v0_1_0.AbciMessage.ConsensusParams\x12\x1f\n\x17\x63onsensus_params_is_set\x18\x04 \x01(\x08\x12H\n\nvalidators\x18\x05 \x01(\x0b\x32\x34.aea.valory.abci.v0_1_0.AbciMessage.ValidatorUpdates\x12\x17\n\x0f\x61pp_state_bytes\x18\x06 \x01(\x0c\x12\x16\n\x0einitial_height\x18\x07 \x01(\x05\x1a]\n\x1aRequest_Query_Performative\x12\x12\n\nquery_data\x18\x01 \x01(\x0c\x12\x0c\n\x04path\x18\x02 \x01(\t\x12\x0e\n\x06height\x18\x03 \x01(\x05\x12\r\n\x05prove\x18\x04 \x01(\x08\x1a\x87\x02\n Request_Begin_Block_Performative\x12\x0c\n\x04hash\x18\x01 \x01(\x0c\x12:\n\x06header\x18\x02 \x01(\x0b\x32*.aea.valory.abci.v0_1_0.AbciMessage.Header\x12L\n\x10last_commit_info\x18\x03 \x01(\x0b\x32\x32.aea.valory.abci.v0_1_0.AbciMessage.LastCommitInfo\x12K\n\x14\x62yzantine_validators\x18\x04 \x01(\x0b\x32-.aea.valory.abci.v0_1_0.AbciMessage.Evidences\x1aj\n\x1dRequest_Check_Tx_Performative\x12\n\n\x02tx\x18\x01 \x01(\x0c\x12=\n\x04type\x18\x02 \x01(\x0b\x32/.aea.valory.abci.v0_1_0.AbciMessage.CheckTxType\x1a-\n\x1fRequest_Deliver_Tx_Performative\x12\n\n\x02tx\x18\x01 \x01(\x0c\x1a\x30\n\x1eRequest_End_Block_Performative\x12\x0e\n\x06height\x18\x01 \x01(\x05\x1a\x1d\n\x1bRequest_Commit_Performative\x1a%\n#Request_List_Snapshots_Performative\x1aw\n#Request_Offer_Snapshot_Performative\x12>\n\x08snapshot\x18\x01 \x01(\x0b\x32,.aea.valory.abci.v0_1_0.AbciMessage.Snapshot\x12\x10\n\x08\x61pp_hash\x18\x02 \x01(\x0c\x1a_\n(Request_Load_Snapshot_Chunk_Performative\x12\x0e\n\x06height\x18\x01 \x01(\x05\x12\x0e\n\x06\x66ormat\x18\x02 \x01(\x05\x12\x13\n\x0b\x63hunk_index\x18\x03 \x01(\x05\x1a_\n)Request_Apply_Snapshot_Chunk_Performative\x12\r\n\x05index\x18\x01 \x01(\x05\x12\r\n\x05\x63hunk\x18\x02 \x01(\x0c\x12\x14\n\x0c\x63hunk_sender\x18\x03 \x01(\t\x1a\x30\n\x1fResponse_Exception_Performative\x12\r\n\x05\x65rror\x18\x01 \x01(\t\x1a-\n\x1aResponse_Echo_Performative\x12\x0f\n\x07message\x18\x01 \x01(\t\x1a\x1d\n\x1bResponse_Flush_Performative\x1a\x8d\x01\n\x1aResponse_Info_Performative\x12\x11\n\tinfo_data\x18\x01 \x01(\t\x12\x0f\n\x07version\x18\x02 \x01(\t\x12\x13\n\x0b\x61pp_version\x18\x03 \x01(\x05\x12\x19\n\x11last_block_height\x18\x04 \x01(\x05\x12\x1b\n\x13last_block_app_hash\x18\x05 \x01(\x0c\x1aK\n Response_Set_Option_Performative\x12\x0c\n\x04\x63ode\x18\x01 \x01(\x05\x12\x0b\n\x03log\x18\x02 \x01(\t\x12\x0c\n\x04info\x18\x03 \x01(\t\x1a\xee\x01\n Response_Init_Chain_Performative\x12M\n\x10\x63onsensus_params\x18\x01 \x01(\x0b\x32\x33.aea.valory.abci.v0_1_0.AbciMessage.ConsensusParams\x12\x1f\n\x17\x63onsensus_params_is_set\x18\x02 \x01(\x08\x12H\n\nvalidators\x18\x03 \x01(\x0b\x32\x34.aea.valory.abci.v0_1_0.AbciMessage.ValidatorUpdates\x12\x10\n\x08\x61pp_hash\x18\x04 \x01(\x0c\x1a\xd5\x01\n\x1bResponse_Query_Performative\x12\x0c\n\x04\x63ode\x18\x01 \x01(\x05\x12\x0b\n\x03log\x18\x02 \x01(\t\x12\x0c\n\x04info\x18\x03 \x01(\t\x12\r\n\x05index\x18\x04 \x01(\x05\x12\x0b\n\x03key\x18\x05 \x01(\x0c\x12\r\n\x05value\x18\x06 \x01(\x0c\x12?\n\tproof_ops\x18\x07 \x01(\x0b\x32,.aea.valory.abci.v0_1_0.AbciMessage.ProofOps\x12\x0e\n\x06height\x18\x08 \x01(\x05\x12\x11\n\tcodespace\x18\t \x01(\t\x1a_\n!Response_Begin_Block_Performative\x12:\n\x06\x65vents\x18\x01 \x01(\x0b\x32*.aea.valory.abci.v0_1_0.AbciMessage.Events\x1a\xcc\x01\n\x1eResponse_Check_Tx_Performative\x12\x0c\n\x04\x63ode\x18\x01 \x01(\x05\x12\x0c\n\x04\x64\x61ta\x18\x02 \x01(\x0c\x12\x0b\n\x03log\x18\x03 \x01(\t\x12\x0c\n\x04info\x18\x04 \x01(\t\x12\x12\n\ngas_wanted\x18\x05 \x01(\x05\x12\x10\n\x08gas_used\x18\x06 \x01(\x05\x12:\n\x06\x65vents\x18\x07 \x01(\x0b\x32*.aea.valory.abci.v0_1_0.AbciMessage.Events\x12\x11\n\tcodespace\x18\x08 \x01(\t\x1a\xce\x01\n Response_Deliver_Tx_Performative\x12\x0c\n\x04\x63ode\x18\x01 \x01(\x05\x12\x0c\n\x04\x64\x61ta\x18\x02 \x01(\x0c\x12\x0b\n\x03log\x18\x03 \x01(\t\x12\x0c\n\x04info\x18\x04 \x01(\t\x12\x12\n\ngas_wanted\x18\x05 \x01(\x05\x12\x10\n\x08gas_used\x18\x06 \x01(\x05\x12:\n\x06\x65vents\x18\x07 \x01(\x0b\x32*.aea.valory.abci.v0_1_0.AbciMessage.Events\x12\x11\n\tcodespace\x18\x08 \x01(\t\x1a\xac\x02\n\x1fResponse_End_Block_Performative\x12O\n\x11validator_updates\x18\x01 \x01(\x0b\x32\x34.aea.valory.abci.v0_1_0.AbciMessage.ValidatorUpdates\x12T\n\x17\x63onsensus_param_updates\x18\x02 \x01(\x0b\x32\x33.aea.valory.abci.v0_1_0.AbciMessage.ConsensusParams\x12&\n\x1e\x63onsensus_param_updates_is_set\x18\x03 \x01(\x08\x12:\n\x06\x65vents\x18\x04 \x01(\x0b\x32*.aea.valory.abci.v0_1_0.AbciMessage.Events\x1a\x43\n\x1cResponse_Commit_Performative\x12\x0c\n\x04\x64\x61ta\x18\x01 \x01(\x0c\x12\x15\n\rretain_height\x18\x02 \x01(\x05\x1ah\n$Response_List_Snapshots_Performative\x12@\n\tsnapshots\x18\x01 \x01(\x0b\x32-.aea.valory.abci.v0_1_0.AbciMessage.SnapShots\x1a\x62\n$Response_Offer_Snapshot_Performative\x12:\n\x06result\x18\x01 \x01(\x0b\x32*.aea.valory.abci.v0_1_0.AbciMessage.Result\x1a:\n)Response_Load_Snapshot_Chunk_Performative\x12\r\n\x05\x63hunk\x18\x01 \x01(\x0c\x1a\x98\x01\n*Response_Apply_Snapshot_Chunk_Performative\x12:\n\x06result\x18\x01 \x01(\x0b\x32*.aea.valory.abci.v0_1_0.AbciMessage.Result\x12\x16\n\x0erefetch_chunks\x18\x02 \x03(\x05\x12\x16\n\x0ereject_senders\x18\x03 \x03(\t\x1ai\n\x12\x44ummy_Performative\x12S\n\x16\x64ummy_consensus_params\x18\x01 \x01(\x0b\x32\x33.aea.valory.abci.v0_1_0.AbciMessage.ConsensusParamsB\x0e\n\x0cperformativeb\x06proto3' ) - -_ABCIMESSAGE = DESCRIPTOR.message_types_by_name["AbciMessage"] -_ABCIMESSAGE_CHECKTXTYPE = _ABCIMESSAGE.nested_types_by_name["CheckTxType"] -_ABCIMESSAGE_CONSENSUSPARAMS = _ABCIMESSAGE.nested_types_by_name["ConsensusParams"] -_ABCIMESSAGE_CONSENSUSPARAMS_DURATION = ( - _ABCIMESSAGE_CONSENSUSPARAMS.nested_types_by_name["Duration"] -) -_ABCIMESSAGE_CONSENSUSPARAMS_BLOCKPARAMS = ( - _ABCIMESSAGE_CONSENSUSPARAMS.nested_types_by_name["BlockParams"] -) -_ABCIMESSAGE_CONSENSUSPARAMS_EVIDENCEPARAMS = ( - _ABCIMESSAGE_CONSENSUSPARAMS.nested_types_by_name["EvidenceParams"] -) -_ABCIMESSAGE_CONSENSUSPARAMS_VALIDATORPARAMS = ( - _ABCIMESSAGE_CONSENSUSPARAMS.nested_types_by_name["ValidatorParams"] -) -_ABCIMESSAGE_CONSENSUSPARAMS_VERSIONPARAMS = ( - _ABCIMESSAGE_CONSENSUSPARAMS.nested_types_by_name["VersionParams"] -) -_ABCIMESSAGE_EVENTS = _ABCIMESSAGE.nested_types_by_name["Events"] -_ABCIMESSAGE_EVENTS_EVENTATTRIBUTE = _ABCIMESSAGE_EVENTS.nested_types_by_name[ - "EventAttribute" -] -_ABCIMESSAGE_EVENTS_EVENT = _ABCIMESSAGE_EVENTS.nested_types_by_name["Event"] -_ABCIMESSAGE_EVIDENCES = _ABCIMESSAGE.nested_types_by_name["Evidences"] -_ABCIMESSAGE_EVIDENCES_EVIDENCE = _ABCIMESSAGE_EVIDENCES.nested_types_by_name[ - "Evidence" -] -_ABCIMESSAGE_HEADER = _ABCIMESSAGE.nested_types_by_name["Header"] -_ABCIMESSAGE_HEADER_CONSENSUSVERSION = _ABCIMESSAGE_HEADER.nested_types_by_name[ - "ConsensusVersion" -] -_ABCIMESSAGE_HEADER_BLOCKID = _ABCIMESSAGE_HEADER.nested_types_by_name["BlockID"] -_ABCIMESSAGE_HEADER_PARTSETHEADER = _ABCIMESSAGE_HEADER.nested_types_by_name[ - "PartSetHeader" -] -_ABCIMESSAGE_LASTCOMMITINFO = _ABCIMESSAGE.nested_types_by_name["LastCommitInfo"] -_ABCIMESSAGE_LASTCOMMITINFO_VALIDATOR = ( - _ABCIMESSAGE_LASTCOMMITINFO.nested_types_by_name["Validator"] -) -_ABCIMESSAGE_LASTCOMMITINFO_VOTEINFO = _ABCIMESSAGE_LASTCOMMITINFO.nested_types_by_name[ - "VoteInfo" -] -_ABCIMESSAGE_PROOFOPS = _ABCIMESSAGE.nested_types_by_name["ProofOps"] -_ABCIMESSAGE_PROOFOPS_PROOFOP = _ABCIMESSAGE_PROOFOPS.nested_types_by_name["ProofOp"] -_ABCIMESSAGE_RESULT = _ABCIMESSAGE.nested_types_by_name["Result"] -_ABCIMESSAGE_SNAPSHOTS = _ABCIMESSAGE.nested_types_by_name["SnapShots"] -_ABCIMESSAGE_SNAPSHOT = _ABCIMESSAGE.nested_types_by_name["Snapshot"] -_ABCIMESSAGE_TIMESTAMP = _ABCIMESSAGE.nested_types_by_name["Timestamp"] -_ABCIMESSAGE_VALIDATORUPDATES = _ABCIMESSAGE.nested_types_by_name["ValidatorUpdates"] -_ABCIMESSAGE_VALIDATORUPDATES_PUBLICKEY = ( - _ABCIMESSAGE_VALIDATORUPDATES.nested_types_by_name["PublicKey"] -) -_ABCIMESSAGE_VALIDATORUPDATES_VALIDATORUPDATE = ( - _ABCIMESSAGE_VALIDATORUPDATES.nested_types_by_name["ValidatorUpdate"] -) -_ABCIMESSAGE_REQUEST_ECHO_PERFORMATIVE = _ABCIMESSAGE.nested_types_by_name[ - "Request_Echo_Performative" -] -_ABCIMESSAGE_REQUEST_FLUSH_PERFORMATIVE = _ABCIMESSAGE.nested_types_by_name[ - "Request_Flush_Performative" -] -_ABCIMESSAGE_REQUEST_INFO_PERFORMATIVE = _ABCIMESSAGE.nested_types_by_name[ - "Request_Info_Performative" -] -_ABCIMESSAGE_REQUEST_SET_OPTION_PERFORMATIVE = _ABCIMESSAGE.nested_types_by_name[ - "Request_Set_Option_Performative" -] -_ABCIMESSAGE_REQUEST_INIT_CHAIN_PERFORMATIVE = _ABCIMESSAGE.nested_types_by_name[ - "Request_Init_Chain_Performative" -] -_ABCIMESSAGE_REQUEST_QUERY_PERFORMATIVE = _ABCIMESSAGE.nested_types_by_name[ - "Request_Query_Performative" -] -_ABCIMESSAGE_REQUEST_BEGIN_BLOCK_PERFORMATIVE = _ABCIMESSAGE.nested_types_by_name[ - "Request_Begin_Block_Performative" -] -_ABCIMESSAGE_REQUEST_CHECK_TX_PERFORMATIVE = _ABCIMESSAGE.nested_types_by_name[ - "Request_Check_Tx_Performative" -] -_ABCIMESSAGE_REQUEST_DELIVER_TX_PERFORMATIVE = _ABCIMESSAGE.nested_types_by_name[ - "Request_Deliver_Tx_Performative" -] -_ABCIMESSAGE_REQUEST_END_BLOCK_PERFORMATIVE = _ABCIMESSAGE.nested_types_by_name[ - "Request_End_Block_Performative" -] -_ABCIMESSAGE_REQUEST_COMMIT_PERFORMATIVE = _ABCIMESSAGE.nested_types_by_name[ - "Request_Commit_Performative" -] -_ABCIMESSAGE_REQUEST_LIST_SNAPSHOTS_PERFORMATIVE = _ABCIMESSAGE.nested_types_by_name[ - "Request_List_Snapshots_Performative" -] -_ABCIMESSAGE_REQUEST_OFFER_SNAPSHOT_PERFORMATIVE = _ABCIMESSAGE.nested_types_by_name[ - "Request_Offer_Snapshot_Performative" -] -_ABCIMESSAGE_REQUEST_LOAD_SNAPSHOT_CHUNK_PERFORMATIVE = ( - _ABCIMESSAGE.nested_types_by_name["Request_Load_Snapshot_Chunk_Performative"] -) -_ABCIMESSAGE_REQUEST_APPLY_SNAPSHOT_CHUNK_PERFORMATIVE = ( - _ABCIMESSAGE.nested_types_by_name["Request_Apply_Snapshot_Chunk_Performative"] -) -_ABCIMESSAGE_RESPONSE_EXCEPTION_PERFORMATIVE = _ABCIMESSAGE.nested_types_by_name[ - "Response_Exception_Performative" -] -_ABCIMESSAGE_RESPONSE_ECHO_PERFORMATIVE = _ABCIMESSAGE.nested_types_by_name[ - "Response_Echo_Performative" -] -_ABCIMESSAGE_RESPONSE_FLUSH_PERFORMATIVE = _ABCIMESSAGE.nested_types_by_name[ - "Response_Flush_Performative" -] -_ABCIMESSAGE_RESPONSE_INFO_PERFORMATIVE = _ABCIMESSAGE.nested_types_by_name[ - "Response_Info_Performative" -] -_ABCIMESSAGE_RESPONSE_SET_OPTION_PERFORMATIVE = _ABCIMESSAGE.nested_types_by_name[ - "Response_Set_Option_Performative" -] -_ABCIMESSAGE_RESPONSE_INIT_CHAIN_PERFORMATIVE = _ABCIMESSAGE.nested_types_by_name[ - "Response_Init_Chain_Performative" -] -_ABCIMESSAGE_RESPONSE_QUERY_PERFORMATIVE = _ABCIMESSAGE.nested_types_by_name[ - "Response_Query_Performative" -] -_ABCIMESSAGE_RESPONSE_BEGIN_BLOCK_PERFORMATIVE = _ABCIMESSAGE.nested_types_by_name[ - "Response_Begin_Block_Performative" -] -_ABCIMESSAGE_RESPONSE_CHECK_TX_PERFORMATIVE = _ABCIMESSAGE.nested_types_by_name[ - "Response_Check_Tx_Performative" -] -_ABCIMESSAGE_RESPONSE_DELIVER_TX_PERFORMATIVE = _ABCIMESSAGE.nested_types_by_name[ - "Response_Deliver_Tx_Performative" -] -_ABCIMESSAGE_RESPONSE_END_BLOCK_PERFORMATIVE = _ABCIMESSAGE.nested_types_by_name[ - "Response_End_Block_Performative" -] -_ABCIMESSAGE_RESPONSE_COMMIT_PERFORMATIVE = _ABCIMESSAGE.nested_types_by_name[ - "Response_Commit_Performative" -] -_ABCIMESSAGE_RESPONSE_LIST_SNAPSHOTS_PERFORMATIVE = _ABCIMESSAGE.nested_types_by_name[ - "Response_List_Snapshots_Performative" -] -_ABCIMESSAGE_RESPONSE_OFFER_SNAPSHOT_PERFORMATIVE = _ABCIMESSAGE.nested_types_by_name[ - "Response_Offer_Snapshot_Performative" -] -_ABCIMESSAGE_RESPONSE_LOAD_SNAPSHOT_CHUNK_PERFORMATIVE = ( - _ABCIMESSAGE.nested_types_by_name["Response_Load_Snapshot_Chunk_Performative"] -) -_ABCIMESSAGE_RESPONSE_APPLY_SNAPSHOT_CHUNK_PERFORMATIVE = ( - _ABCIMESSAGE.nested_types_by_name["Response_Apply_Snapshot_Chunk_Performative"] -) -_ABCIMESSAGE_DUMMY_PERFORMATIVE = _ABCIMESSAGE.nested_types_by_name[ - "Dummy_Performative" -] -_ABCIMESSAGE_CHECKTXTYPE__CHECKTXTYPE = _ABCIMESSAGE_CHECKTXTYPE.enum_types_by_name[ - "_CheckTxType" -] -_ABCIMESSAGE_EVIDENCES_EVIDENCE_EVIDENCETYPE = ( - _ABCIMESSAGE_EVIDENCES_EVIDENCE.enum_types_by_name["EvidenceType"] -) -_ABCIMESSAGE_RESULT_RESULTTYPE = _ABCIMESSAGE_RESULT.enum_types_by_name["ResultType"] -AbciMessage = _reflection.GeneratedProtocolMessageType( - "AbciMessage", - (_message.Message,), - { - "CheckTxType": _reflection.GeneratedProtocolMessageType( - "CheckTxType", - (_message.Message,), - { - "DESCRIPTOR": _ABCIMESSAGE_CHECKTXTYPE, - "__module__": "abci_pb2" - # @@protoc_insertion_point(class_scope:aea.valory.abci.v0_1_0.AbciMessage.CheckTxType) - }, - ), - "ConsensusParams": _reflection.GeneratedProtocolMessageType( - "ConsensusParams", - (_message.Message,), - { - "Duration": _reflection.GeneratedProtocolMessageType( - "Duration", - (_message.Message,), - { - "DESCRIPTOR": _ABCIMESSAGE_CONSENSUSPARAMS_DURATION, - "__module__": "abci_pb2" - # @@protoc_insertion_point(class_scope:aea.valory.abci.v0_1_0.AbciMessage.ConsensusParams.Duration) - }, - ), - "BlockParams": _reflection.GeneratedProtocolMessageType( - "BlockParams", - (_message.Message,), - { - "DESCRIPTOR": _ABCIMESSAGE_CONSENSUSPARAMS_BLOCKPARAMS, - "__module__": "abci_pb2" - # @@protoc_insertion_point(class_scope:aea.valory.abci.v0_1_0.AbciMessage.ConsensusParams.BlockParams) - }, - ), - "EvidenceParams": _reflection.GeneratedProtocolMessageType( - "EvidenceParams", - (_message.Message,), - { - "DESCRIPTOR": _ABCIMESSAGE_CONSENSUSPARAMS_EVIDENCEPARAMS, - "__module__": "abci_pb2" - # @@protoc_insertion_point(class_scope:aea.valory.abci.v0_1_0.AbciMessage.ConsensusParams.EvidenceParams) - }, - ), - "ValidatorParams": _reflection.GeneratedProtocolMessageType( - "ValidatorParams", - (_message.Message,), - { - "DESCRIPTOR": _ABCIMESSAGE_CONSENSUSPARAMS_VALIDATORPARAMS, - "__module__": "abci_pb2" - # @@protoc_insertion_point(class_scope:aea.valory.abci.v0_1_0.AbciMessage.ConsensusParams.ValidatorParams) - }, - ), - "VersionParams": _reflection.GeneratedProtocolMessageType( - "VersionParams", - (_message.Message,), - { - "DESCRIPTOR": _ABCIMESSAGE_CONSENSUSPARAMS_VERSIONPARAMS, - "__module__": "abci_pb2" - # @@protoc_insertion_point(class_scope:aea.valory.abci.v0_1_0.AbciMessage.ConsensusParams.VersionParams) - }, - ), - "DESCRIPTOR": _ABCIMESSAGE_CONSENSUSPARAMS, - "__module__": "abci_pb2" - # @@protoc_insertion_point(class_scope:aea.valory.abci.v0_1_0.AbciMessage.ConsensusParams) - }, - ), - "Events": _reflection.GeneratedProtocolMessageType( - "Events", - (_message.Message,), - { - "EventAttribute": _reflection.GeneratedProtocolMessageType( - "EventAttribute", - (_message.Message,), - { - "DESCRIPTOR": _ABCIMESSAGE_EVENTS_EVENTATTRIBUTE, - "__module__": "abci_pb2" - # @@protoc_insertion_point(class_scope:aea.valory.abci.v0_1_0.AbciMessage.Events.EventAttribute) - }, - ), - "Event": _reflection.GeneratedProtocolMessageType( - "Event", - (_message.Message,), - { - "DESCRIPTOR": _ABCIMESSAGE_EVENTS_EVENT, - "__module__": "abci_pb2" - # @@protoc_insertion_point(class_scope:aea.valory.abci.v0_1_0.AbciMessage.Events.Event) - }, - ), - "DESCRIPTOR": _ABCIMESSAGE_EVENTS, - "__module__": "abci_pb2" - # @@protoc_insertion_point(class_scope:aea.valory.abci.v0_1_0.AbciMessage.Events) - }, - ), - "Evidences": _reflection.GeneratedProtocolMessageType( - "Evidences", - (_message.Message,), - { - "Evidence": _reflection.GeneratedProtocolMessageType( - "Evidence", - (_message.Message,), - { - "DESCRIPTOR": _ABCIMESSAGE_EVIDENCES_EVIDENCE, - "__module__": "abci_pb2" - # @@protoc_insertion_point(class_scope:aea.valory.abci.v0_1_0.AbciMessage.Evidences.Evidence) - }, - ), - "DESCRIPTOR": _ABCIMESSAGE_EVIDENCES, - "__module__": "abci_pb2" - # @@protoc_insertion_point(class_scope:aea.valory.abci.v0_1_0.AbciMessage.Evidences) - }, - ), - "Header": _reflection.GeneratedProtocolMessageType( - "Header", - (_message.Message,), - { - "ConsensusVersion": _reflection.GeneratedProtocolMessageType( - "ConsensusVersion", - (_message.Message,), - { - "DESCRIPTOR": _ABCIMESSAGE_HEADER_CONSENSUSVERSION, - "__module__": "abci_pb2" - # @@protoc_insertion_point(class_scope:aea.valory.abci.v0_1_0.AbciMessage.Header.ConsensusVersion) - }, - ), - "BlockID": _reflection.GeneratedProtocolMessageType( - "BlockID", - (_message.Message,), - { - "DESCRIPTOR": _ABCIMESSAGE_HEADER_BLOCKID, - "__module__": "abci_pb2" - # @@protoc_insertion_point(class_scope:aea.valory.abci.v0_1_0.AbciMessage.Header.BlockID) - }, - ), - "PartSetHeader": _reflection.GeneratedProtocolMessageType( - "PartSetHeader", - (_message.Message,), - { - "DESCRIPTOR": _ABCIMESSAGE_HEADER_PARTSETHEADER, - "__module__": "abci_pb2" - # @@protoc_insertion_point(class_scope:aea.valory.abci.v0_1_0.AbciMessage.Header.PartSetHeader) - }, - ), - "DESCRIPTOR": _ABCIMESSAGE_HEADER, - "__module__": "abci_pb2" - # @@protoc_insertion_point(class_scope:aea.valory.abci.v0_1_0.AbciMessage.Header) - }, - ), - "LastCommitInfo": _reflection.GeneratedProtocolMessageType( - "LastCommitInfo", - (_message.Message,), - { - "Validator": _reflection.GeneratedProtocolMessageType( - "Validator", - (_message.Message,), - { - "DESCRIPTOR": _ABCIMESSAGE_LASTCOMMITINFO_VALIDATOR, - "__module__": "abci_pb2" - # @@protoc_insertion_point(class_scope:aea.valory.abci.v0_1_0.AbciMessage.LastCommitInfo.Validator) - }, - ), - "VoteInfo": _reflection.GeneratedProtocolMessageType( - "VoteInfo", - (_message.Message,), - { - "DESCRIPTOR": _ABCIMESSAGE_LASTCOMMITINFO_VOTEINFO, - "__module__": "abci_pb2" - # @@protoc_insertion_point(class_scope:aea.valory.abci.v0_1_0.AbciMessage.LastCommitInfo.VoteInfo) - }, - ), - "DESCRIPTOR": _ABCIMESSAGE_LASTCOMMITINFO, - "__module__": "abci_pb2" - # @@protoc_insertion_point(class_scope:aea.valory.abci.v0_1_0.AbciMessage.LastCommitInfo) - }, - ), - "ProofOps": _reflection.GeneratedProtocolMessageType( - "ProofOps", - (_message.Message,), - { - "ProofOp": _reflection.GeneratedProtocolMessageType( - "ProofOp", - (_message.Message,), - { - "DESCRIPTOR": _ABCIMESSAGE_PROOFOPS_PROOFOP, - "__module__": "abci_pb2" - # @@protoc_insertion_point(class_scope:aea.valory.abci.v0_1_0.AbciMessage.ProofOps.ProofOp) - }, - ), - "DESCRIPTOR": _ABCIMESSAGE_PROOFOPS, - "__module__": "abci_pb2" - # @@protoc_insertion_point(class_scope:aea.valory.abci.v0_1_0.AbciMessage.ProofOps) - }, - ), - "Result": _reflection.GeneratedProtocolMessageType( - "Result", - (_message.Message,), - { - "DESCRIPTOR": _ABCIMESSAGE_RESULT, - "__module__": "abci_pb2" - # @@protoc_insertion_point(class_scope:aea.valory.abci.v0_1_0.AbciMessage.Result) - }, - ), - "SnapShots": _reflection.GeneratedProtocolMessageType( - "SnapShots", - (_message.Message,), - { - "DESCRIPTOR": _ABCIMESSAGE_SNAPSHOTS, - "__module__": "abci_pb2" - # @@protoc_insertion_point(class_scope:aea.valory.abci.v0_1_0.AbciMessage.SnapShots) - }, - ), - "Snapshot": _reflection.GeneratedProtocolMessageType( - "Snapshot", - (_message.Message,), - { - "DESCRIPTOR": _ABCIMESSAGE_SNAPSHOT, - "__module__": "abci_pb2" - # @@protoc_insertion_point(class_scope:aea.valory.abci.v0_1_0.AbciMessage.Snapshot) - }, - ), - "Timestamp": _reflection.GeneratedProtocolMessageType( - "Timestamp", - (_message.Message,), - { - "DESCRIPTOR": _ABCIMESSAGE_TIMESTAMP, - "__module__": "abci_pb2" - # @@protoc_insertion_point(class_scope:aea.valory.abci.v0_1_0.AbciMessage.Timestamp) - }, - ), - "ValidatorUpdates": _reflection.GeneratedProtocolMessageType( - "ValidatorUpdates", - (_message.Message,), - { - "PublicKey": _reflection.GeneratedProtocolMessageType( - "PublicKey", - (_message.Message,), - { - "DESCRIPTOR": _ABCIMESSAGE_VALIDATORUPDATES_PUBLICKEY, - "__module__": "abci_pb2" - # @@protoc_insertion_point(class_scope:aea.valory.abci.v0_1_0.AbciMessage.ValidatorUpdates.PublicKey) - }, - ), - "ValidatorUpdate": _reflection.GeneratedProtocolMessageType( - "ValidatorUpdate", - (_message.Message,), - { - "DESCRIPTOR": _ABCIMESSAGE_VALIDATORUPDATES_VALIDATORUPDATE, - "__module__": "abci_pb2" - # @@protoc_insertion_point(class_scope:aea.valory.abci.v0_1_0.AbciMessage.ValidatorUpdates.ValidatorUpdate) - }, - ), - "DESCRIPTOR": _ABCIMESSAGE_VALIDATORUPDATES, - "__module__": "abci_pb2" - # @@protoc_insertion_point(class_scope:aea.valory.abci.v0_1_0.AbciMessage.ValidatorUpdates) - }, - ), - "Request_Echo_Performative": _reflection.GeneratedProtocolMessageType( - "Request_Echo_Performative", - (_message.Message,), - { - "DESCRIPTOR": _ABCIMESSAGE_REQUEST_ECHO_PERFORMATIVE, - "__module__": "abci_pb2" - # @@protoc_insertion_point(class_scope:aea.valory.abci.v0_1_0.AbciMessage.Request_Echo_Performative) - }, - ), - "Request_Flush_Performative": _reflection.GeneratedProtocolMessageType( - "Request_Flush_Performative", - (_message.Message,), - { - "DESCRIPTOR": _ABCIMESSAGE_REQUEST_FLUSH_PERFORMATIVE, - "__module__": "abci_pb2" - # @@protoc_insertion_point(class_scope:aea.valory.abci.v0_1_0.AbciMessage.Request_Flush_Performative) - }, - ), - "Request_Info_Performative": _reflection.GeneratedProtocolMessageType( - "Request_Info_Performative", - (_message.Message,), - { - "DESCRIPTOR": _ABCIMESSAGE_REQUEST_INFO_PERFORMATIVE, - "__module__": "abci_pb2" - # @@protoc_insertion_point(class_scope:aea.valory.abci.v0_1_0.AbciMessage.Request_Info_Performative) - }, - ), - "Request_Set_Option_Performative": _reflection.GeneratedProtocolMessageType( - "Request_Set_Option_Performative", - (_message.Message,), - { - "DESCRIPTOR": _ABCIMESSAGE_REQUEST_SET_OPTION_PERFORMATIVE, - "__module__": "abci_pb2" - # @@protoc_insertion_point(class_scope:aea.valory.abci.v0_1_0.AbciMessage.Request_Set_Option_Performative) - }, - ), - "Request_Init_Chain_Performative": _reflection.GeneratedProtocolMessageType( - "Request_Init_Chain_Performative", - (_message.Message,), - { - "DESCRIPTOR": _ABCIMESSAGE_REQUEST_INIT_CHAIN_PERFORMATIVE, - "__module__": "abci_pb2" - # @@protoc_insertion_point(class_scope:aea.valory.abci.v0_1_0.AbciMessage.Request_Init_Chain_Performative) - }, - ), - "Request_Query_Performative": _reflection.GeneratedProtocolMessageType( - "Request_Query_Performative", - (_message.Message,), - { - "DESCRIPTOR": _ABCIMESSAGE_REQUEST_QUERY_PERFORMATIVE, - "__module__": "abci_pb2" - # @@protoc_insertion_point(class_scope:aea.valory.abci.v0_1_0.AbciMessage.Request_Query_Performative) - }, - ), - "Request_Begin_Block_Performative": _reflection.GeneratedProtocolMessageType( - "Request_Begin_Block_Performative", - (_message.Message,), - { - "DESCRIPTOR": _ABCIMESSAGE_REQUEST_BEGIN_BLOCK_PERFORMATIVE, - "__module__": "abci_pb2" - # @@protoc_insertion_point(class_scope:aea.valory.abci.v0_1_0.AbciMessage.Request_Begin_Block_Performative) - }, - ), - "Request_Check_Tx_Performative": _reflection.GeneratedProtocolMessageType( - "Request_Check_Tx_Performative", - (_message.Message,), - { - "DESCRIPTOR": _ABCIMESSAGE_REQUEST_CHECK_TX_PERFORMATIVE, - "__module__": "abci_pb2" - # @@protoc_insertion_point(class_scope:aea.valory.abci.v0_1_0.AbciMessage.Request_Check_Tx_Performative) - }, - ), - "Request_Deliver_Tx_Performative": _reflection.GeneratedProtocolMessageType( - "Request_Deliver_Tx_Performative", - (_message.Message,), - { - "DESCRIPTOR": _ABCIMESSAGE_REQUEST_DELIVER_TX_PERFORMATIVE, - "__module__": "abci_pb2" - # @@protoc_insertion_point(class_scope:aea.valory.abci.v0_1_0.AbciMessage.Request_Deliver_Tx_Performative) - }, - ), - "Request_End_Block_Performative": _reflection.GeneratedProtocolMessageType( - "Request_End_Block_Performative", - (_message.Message,), - { - "DESCRIPTOR": _ABCIMESSAGE_REQUEST_END_BLOCK_PERFORMATIVE, - "__module__": "abci_pb2" - # @@protoc_insertion_point(class_scope:aea.valory.abci.v0_1_0.AbciMessage.Request_End_Block_Performative) - }, - ), - "Request_Commit_Performative": _reflection.GeneratedProtocolMessageType( - "Request_Commit_Performative", - (_message.Message,), - { - "DESCRIPTOR": _ABCIMESSAGE_REQUEST_COMMIT_PERFORMATIVE, - "__module__": "abci_pb2" - # @@protoc_insertion_point(class_scope:aea.valory.abci.v0_1_0.AbciMessage.Request_Commit_Performative) - }, - ), - "Request_List_Snapshots_Performative": _reflection.GeneratedProtocolMessageType( - "Request_List_Snapshots_Performative", - (_message.Message,), - { - "DESCRIPTOR": _ABCIMESSAGE_REQUEST_LIST_SNAPSHOTS_PERFORMATIVE, - "__module__": "abci_pb2" - # @@protoc_insertion_point(class_scope:aea.valory.abci.v0_1_0.AbciMessage.Request_List_Snapshots_Performative) - }, - ), - "Request_Offer_Snapshot_Performative": _reflection.GeneratedProtocolMessageType( - "Request_Offer_Snapshot_Performative", - (_message.Message,), - { - "DESCRIPTOR": _ABCIMESSAGE_REQUEST_OFFER_SNAPSHOT_PERFORMATIVE, - "__module__": "abci_pb2" - # @@protoc_insertion_point(class_scope:aea.valory.abci.v0_1_0.AbciMessage.Request_Offer_Snapshot_Performative) - }, - ), - "Request_Load_Snapshot_Chunk_Performative": _reflection.GeneratedProtocolMessageType( - "Request_Load_Snapshot_Chunk_Performative", - (_message.Message,), - { - "DESCRIPTOR": _ABCIMESSAGE_REQUEST_LOAD_SNAPSHOT_CHUNK_PERFORMATIVE, - "__module__": "abci_pb2" - # @@protoc_insertion_point(class_scope:aea.valory.abci.v0_1_0.AbciMessage.Request_Load_Snapshot_Chunk_Performative) - }, - ), - "Request_Apply_Snapshot_Chunk_Performative": _reflection.GeneratedProtocolMessageType( - "Request_Apply_Snapshot_Chunk_Performative", - (_message.Message,), - { - "DESCRIPTOR": _ABCIMESSAGE_REQUEST_APPLY_SNAPSHOT_CHUNK_PERFORMATIVE, - "__module__": "abci_pb2" - # @@protoc_insertion_point(class_scope:aea.valory.abci.v0_1_0.AbciMessage.Request_Apply_Snapshot_Chunk_Performative) - }, - ), - "Response_Exception_Performative": _reflection.GeneratedProtocolMessageType( - "Response_Exception_Performative", - (_message.Message,), - { - "DESCRIPTOR": _ABCIMESSAGE_RESPONSE_EXCEPTION_PERFORMATIVE, - "__module__": "abci_pb2" - # @@protoc_insertion_point(class_scope:aea.valory.abci.v0_1_0.AbciMessage.Response_Exception_Performative) - }, - ), - "Response_Echo_Performative": _reflection.GeneratedProtocolMessageType( - "Response_Echo_Performative", - (_message.Message,), - { - "DESCRIPTOR": _ABCIMESSAGE_RESPONSE_ECHO_PERFORMATIVE, - "__module__": "abci_pb2" - # @@protoc_insertion_point(class_scope:aea.valory.abci.v0_1_0.AbciMessage.Response_Echo_Performative) - }, - ), - "Response_Flush_Performative": _reflection.GeneratedProtocolMessageType( - "Response_Flush_Performative", - (_message.Message,), - { - "DESCRIPTOR": _ABCIMESSAGE_RESPONSE_FLUSH_PERFORMATIVE, - "__module__": "abci_pb2" - # @@protoc_insertion_point(class_scope:aea.valory.abci.v0_1_0.AbciMessage.Response_Flush_Performative) - }, - ), - "Response_Info_Performative": _reflection.GeneratedProtocolMessageType( - "Response_Info_Performative", - (_message.Message,), - { - "DESCRIPTOR": _ABCIMESSAGE_RESPONSE_INFO_PERFORMATIVE, - "__module__": "abci_pb2" - # @@protoc_insertion_point(class_scope:aea.valory.abci.v0_1_0.AbciMessage.Response_Info_Performative) - }, - ), - "Response_Set_Option_Performative": _reflection.GeneratedProtocolMessageType( - "Response_Set_Option_Performative", - (_message.Message,), - { - "DESCRIPTOR": _ABCIMESSAGE_RESPONSE_SET_OPTION_PERFORMATIVE, - "__module__": "abci_pb2" - # @@protoc_insertion_point(class_scope:aea.valory.abci.v0_1_0.AbciMessage.Response_Set_Option_Performative) - }, - ), - "Response_Init_Chain_Performative": _reflection.GeneratedProtocolMessageType( - "Response_Init_Chain_Performative", - (_message.Message,), - { - "DESCRIPTOR": _ABCIMESSAGE_RESPONSE_INIT_CHAIN_PERFORMATIVE, - "__module__": "abci_pb2" - # @@protoc_insertion_point(class_scope:aea.valory.abci.v0_1_0.AbciMessage.Response_Init_Chain_Performative) - }, - ), - "Response_Query_Performative": _reflection.GeneratedProtocolMessageType( - "Response_Query_Performative", - (_message.Message,), - { - "DESCRIPTOR": _ABCIMESSAGE_RESPONSE_QUERY_PERFORMATIVE, - "__module__": "abci_pb2" - # @@protoc_insertion_point(class_scope:aea.valory.abci.v0_1_0.AbciMessage.Response_Query_Performative) - }, - ), - "Response_Begin_Block_Performative": _reflection.GeneratedProtocolMessageType( - "Response_Begin_Block_Performative", - (_message.Message,), - { - "DESCRIPTOR": _ABCIMESSAGE_RESPONSE_BEGIN_BLOCK_PERFORMATIVE, - "__module__": "abci_pb2" - # @@protoc_insertion_point(class_scope:aea.valory.abci.v0_1_0.AbciMessage.Response_Begin_Block_Performative) - }, - ), - "Response_Check_Tx_Performative": _reflection.GeneratedProtocolMessageType( - "Response_Check_Tx_Performative", - (_message.Message,), - { - "DESCRIPTOR": _ABCIMESSAGE_RESPONSE_CHECK_TX_PERFORMATIVE, - "__module__": "abci_pb2" - # @@protoc_insertion_point(class_scope:aea.valory.abci.v0_1_0.AbciMessage.Response_Check_Tx_Performative) - }, - ), - "Response_Deliver_Tx_Performative": _reflection.GeneratedProtocolMessageType( - "Response_Deliver_Tx_Performative", - (_message.Message,), - { - "DESCRIPTOR": _ABCIMESSAGE_RESPONSE_DELIVER_TX_PERFORMATIVE, - "__module__": "abci_pb2" - # @@protoc_insertion_point(class_scope:aea.valory.abci.v0_1_0.AbciMessage.Response_Deliver_Tx_Performative) - }, - ), - "Response_End_Block_Performative": _reflection.GeneratedProtocolMessageType( - "Response_End_Block_Performative", - (_message.Message,), - { - "DESCRIPTOR": _ABCIMESSAGE_RESPONSE_END_BLOCK_PERFORMATIVE, - "__module__": "abci_pb2" - # @@protoc_insertion_point(class_scope:aea.valory.abci.v0_1_0.AbciMessage.Response_End_Block_Performative) - }, - ), - "Response_Commit_Performative": _reflection.GeneratedProtocolMessageType( - "Response_Commit_Performative", - (_message.Message,), - { - "DESCRIPTOR": _ABCIMESSAGE_RESPONSE_COMMIT_PERFORMATIVE, - "__module__": "abci_pb2" - # @@protoc_insertion_point(class_scope:aea.valory.abci.v0_1_0.AbciMessage.Response_Commit_Performative) - }, - ), - "Response_List_Snapshots_Performative": _reflection.GeneratedProtocolMessageType( - "Response_List_Snapshots_Performative", - (_message.Message,), - { - "DESCRIPTOR": _ABCIMESSAGE_RESPONSE_LIST_SNAPSHOTS_PERFORMATIVE, - "__module__": "abci_pb2" - # @@protoc_insertion_point(class_scope:aea.valory.abci.v0_1_0.AbciMessage.Response_List_Snapshots_Performative) - }, - ), - "Response_Offer_Snapshot_Performative": _reflection.GeneratedProtocolMessageType( - "Response_Offer_Snapshot_Performative", - (_message.Message,), - { - "DESCRIPTOR": _ABCIMESSAGE_RESPONSE_OFFER_SNAPSHOT_PERFORMATIVE, - "__module__": "abci_pb2" - # @@protoc_insertion_point(class_scope:aea.valory.abci.v0_1_0.AbciMessage.Response_Offer_Snapshot_Performative) - }, - ), - "Response_Load_Snapshot_Chunk_Performative": _reflection.GeneratedProtocolMessageType( - "Response_Load_Snapshot_Chunk_Performative", - (_message.Message,), - { - "DESCRIPTOR": _ABCIMESSAGE_RESPONSE_LOAD_SNAPSHOT_CHUNK_PERFORMATIVE, - "__module__": "abci_pb2" - # @@protoc_insertion_point(class_scope:aea.valory.abci.v0_1_0.AbciMessage.Response_Load_Snapshot_Chunk_Performative) - }, - ), - "Response_Apply_Snapshot_Chunk_Performative": _reflection.GeneratedProtocolMessageType( - "Response_Apply_Snapshot_Chunk_Performative", - (_message.Message,), - { - "DESCRIPTOR": _ABCIMESSAGE_RESPONSE_APPLY_SNAPSHOT_CHUNK_PERFORMATIVE, - "__module__": "abci_pb2" - # @@protoc_insertion_point(class_scope:aea.valory.abci.v0_1_0.AbciMessage.Response_Apply_Snapshot_Chunk_Performative) - }, - ), - "Dummy_Performative": _reflection.GeneratedProtocolMessageType( - "Dummy_Performative", - (_message.Message,), - { - "DESCRIPTOR": _ABCIMESSAGE_DUMMY_PERFORMATIVE, - "__module__": "abci_pb2" - # @@protoc_insertion_point(class_scope:aea.valory.abci.v0_1_0.AbciMessage.Dummy_Performative) - }, - ), - "DESCRIPTOR": _ABCIMESSAGE, - "__module__": "abci_pb2" - # @@protoc_insertion_point(class_scope:aea.valory.abci.v0_1_0.AbciMessage) - }, -) -_sym_db.RegisterMessage(AbciMessage) -_sym_db.RegisterMessage(AbciMessage.CheckTxType) -_sym_db.RegisterMessage(AbciMessage.ConsensusParams) -_sym_db.RegisterMessage(AbciMessage.ConsensusParams.Duration) -_sym_db.RegisterMessage(AbciMessage.ConsensusParams.BlockParams) -_sym_db.RegisterMessage(AbciMessage.ConsensusParams.EvidenceParams) -_sym_db.RegisterMessage(AbciMessage.ConsensusParams.ValidatorParams) -_sym_db.RegisterMessage(AbciMessage.ConsensusParams.VersionParams) -_sym_db.RegisterMessage(AbciMessage.Events) -_sym_db.RegisterMessage(AbciMessage.Events.EventAttribute) -_sym_db.RegisterMessage(AbciMessage.Events.Event) -_sym_db.RegisterMessage(AbciMessage.Evidences) -_sym_db.RegisterMessage(AbciMessage.Evidences.Evidence) -_sym_db.RegisterMessage(AbciMessage.Header) -_sym_db.RegisterMessage(AbciMessage.Header.ConsensusVersion) -_sym_db.RegisterMessage(AbciMessage.Header.BlockID) -_sym_db.RegisterMessage(AbciMessage.Header.PartSetHeader) -_sym_db.RegisterMessage(AbciMessage.LastCommitInfo) -_sym_db.RegisterMessage(AbciMessage.LastCommitInfo.Validator) -_sym_db.RegisterMessage(AbciMessage.LastCommitInfo.VoteInfo) -_sym_db.RegisterMessage(AbciMessage.ProofOps) -_sym_db.RegisterMessage(AbciMessage.ProofOps.ProofOp) -_sym_db.RegisterMessage(AbciMessage.Result) -_sym_db.RegisterMessage(AbciMessage.SnapShots) -_sym_db.RegisterMessage(AbciMessage.Snapshot) -_sym_db.RegisterMessage(AbciMessage.Timestamp) -_sym_db.RegisterMessage(AbciMessage.ValidatorUpdates) -_sym_db.RegisterMessage(AbciMessage.ValidatorUpdates.PublicKey) -_sym_db.RegisterMessage(AbciMessage.ValidatorUpdates.ValidatorUpdate) -_sym_db.RegisterMessage(AbciMessage.Request_Echo_Performative) -_sym_db.RegisterMessage(AbciMessage.Request_Flush_Performative) -_sym_db.RegisterMessage(AbciMessage.Request_Info_Performative) -_sym_db.RegisterMessage(AbciMessage.Request_Set_Option_Performative) -_sym_db.RegisterMessage(AbciMessage.Request_Init_Chain_Performative) -_sym_db.RegisterMessage(AbciMessage.Request_Query_Performative) -_sym_db.RegisterMessage(AbciMessage.Request_Begin_Block_Performative) -_sym_db.RegisterMessage(AbciMessage.Request_Check_Tx_Performative) -_sym_db.RegisterMessage(AbciMessage.Request_Deliver_Tx_Performative) -_sym_db.RegisterMessage(AbciMessage.Request_End_Block_Performative) -_sym_db.RegisterMessage(AbciMessage.Request_Commit_Performative) -_sym_db.RegisterMessage(AbciMessage.Request_List_Snapshots_Performative) -_sym_db.RegisterMessage(AbciMessage.Request_Offer_Snapshot_Performative) -_sym_db.RegisterMessage(AbciMessage.Request_Load_Snapshot_Chunk_Performative) -_sym_db.RegisterMessage(AbciMessage.Request_Apply_Snapshot_Chunk_Performative) -_sym_db.RegisterMessage(AbciMessage.Response_Exception_Performative) -_sym_db.RegisterMessage(AbciMessage.Response_Echo_Performative) -_sym_db.RegisterMessage(AbciMessage.Response_Flush_Performative) -_sym_db.RegisterMessage(AbciMessage.Response_Info_Performative) -_sym_db.RegisterMessage(AbciMessage.Response_Set_Option_Performative) -_sym_db.RegisterMessage(AbciMessage.Response_Init_Chain_Performative) -_sym_db.RegisterMessage(AbciMessage.Response_Query_Performative) -_sym_db.RegisterMessage(AbciMessage.Response_Begin_Block_Performative) -_sym_db.RegisterMessage(AbciMessage.Response_Check_Tx_Performative) -_sym_db.RegisterMessage(AbciMessage.Response_Deliver_Tx_Performative) -_sym_db.RegisterMessage(AbciMessage.Response_End_Block_Performative) -_sym_db.RegisterMessage(AbciMessage.Response_Commit_Performative) -_sym_db.RegisterMessage(AbciMessage.Response_List_Snapshots_Performative) -_sym_db.RegisterMessage(AbciMessage.Response_Offer_Snapshot_Performative) -_sym_db.RegisterMessage(AbciMessage.Response_Load_Snapshot_Chunk_Performative) -_sym_db.RegisterMessage(AbciMessage.Response_Apply_Snapshot_Chunk_Performative) -_sym_db.RegisterMessage(AbciMessage.Dummy_Performative) - +_globals = globals() +_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) +_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, "abci_pb2", _globals) if _descriptor._USE_C_DESCRIPTORS == False: - DESCRIPTOR._options = None - _ABCIMESSAGE._serialized_start = 39 - _ABCIMESSAGE._serialized_end = 10285 - _ABCIMESSAGE_CHECKTXTYPE._serialized_start = 3222 - _ABCIMESSAGE_CHECKTXTYPE._serialized_end = 3349 - _ABCIMESSAGE_CHECKTXTYPE__CHECKTXTYPE._serialized_start = 3313 - _ABCIMESSAGE_CHECKTXTYPE__CHECKTXTYPE._serialized_end = 3349 - _ABCIMESSAGE_CONSENSUSPARAMS._serialized_start = 3352 - _ABCIMESSAGE_CONSENSUSPARAMS._serialized_end = 4036 - _ABCIMESSAGE_CONSENSUSPARAMS_DURATION._serialized_start = 3709 - _ABCIMESSAGE_CONSENSUSPARAMS_DURATION._serialized_end = 3751 - _ABCIMESSAGE_CONSENSUSPARAMS_BLOCKPARAMS._serialized_start = 3753 - _ABCIMESSAGE_CONSENSUSPARAMS_BLOCKPARAMS._serialized_end = 3802 - _ABCIMESSAGE_CONSENSUSPARAMS_EVIDENCEPARAMS._serialized_start = 3805 - _ABCIMESSAGE_CONSENSUSPARAMS_EVIDENCEPARAMS._serialized_end = 3956 - _ABCIMESSAGE_CONSENSUSPARAMS_VALIDATORPARAMS._serialized_start = 3958 - _ABCIMESSAGE_CONSENSUSPARAMS_VALIDATORPARAMS._serialized_end = 3998 - _ABCIMESSAGE_CONSENSUSPARAMS_VERSIONPARAMS._serialized_start = 4000 - _ABCIMESSAGE_CONSENSUSPARAMS_VERSIONPARAMS._serialized_end = 4036 - _ABCIMESSAGE_EVENTS._serialized_start = 4039 - _ABCIMESSAGE_EVENTS._serialized_end = 4276 - _ABCIMESSAGE_EVENTS_EVENTATTRIBUTE._serialized_start = 4115 - _ABCIMESSAGE_EVENTS_EVENTATTRIBUTE._serialized_end = 4174 - _ABCIMESSAGE_EVENTS_EVENT._serialized_start = 4176 - _ABCIMESSAGE_EVENTS_EVENT._serialized_end = 4276 - _ABCIMESSAGE_EVIDENCES._serialized_start = 4279 - _ABCIMESSAGE_EVIDENCES._serialized_end = 4732 - _ABCIMESSAGE_EVIDENCES_EVIDENCE._serialized_start = 4379 - _ABCIMESSAGE_EVIDENCES_EVIDENCE._serialized_end = 4732 - _ABCIMESSAGE_EVIDENCES_EVIDENCE_EVIDENCETYPE._serialized_start = 4660 - _ABCIMESSAGE_EVIDENCES_EVIDENCE_EVIDENCETYPE._serialized_end = 4732 - _ABCIMESSAGE_HEADER._serialized_start = 4735 - _ABCIMESSAGE_HEADER._serialized_end = 5411 - _ABCIMESSAGE_HEADER_CONSENSUSVERSION._serialized_start = 5211 - _ABCIMESSAGE_HEADER_CONSENSUSVERSION._serialized_end = 5257 - _ABCIMESSAGE_HEADER_BLOCKID._serialized_start = 5259 - _ABCIMESSAGE_HEADER_BLOCKID._serialized_end = 5365 - _ABCIMESSAGE_HEADER_PARTSETHEADER._serialized_start = 5367 - _ABCIMESSAGE_HEADER_PARTSETHEADER._serialized_end = 5411 - _ABCIMESSAGE_LASTCOMMITINFO._serialized_start = 5414 - _ABCIMESSAGE_LASTCOMMITINFO._serialized_end = 5686 - _ABCIMESSAGE_LASTCOMMITINFO_VALIDATOR._serialized_start = 5523 - _ABCIMESSAGE_LASTCOMMITINFO_VALIDATOR._serialized_end = 5566 - _ABCIMESSAGE_LASTCOMMITINFO_VOTEINFO._serialized_start = 5568 - _ABCIMESSAGE_LASTCOMMITINFO_VOTEINFO._serialized_end = 5686 - _ABCIMESSAGE_PROOFOPS._serialized_start = 5689 - _ABCIMESSAGE_PROOFOPS._serialized_end = 5818 - _ABCIMESSAGE_PROOFOPS_PROOFOP._serialized_start = 5768 - _ABCIMESSAGE_PROOFOPS_PROOFOP._serialized_end = 5818 - _ABCIMESSAGE_RESULT._serialized_start = 5821 - _ABCIMESSAGE_RESULT._serialized_end = 6005 - _ABCIMESSAGE_RESULT_RESULTTYPE._serialized_start = 5907 - _ABCIMESSAGE_RESULT_RESULTTYPE._serialized_end = 6005 - _ABCIMESSAGE_SNAPSHOTS._serialized_start = 6007 - _ABCIMESSAGE_SNAPSHOTS._serialized_end = 6083 - _ABCIMESSAGE_SNAPSHOT._serialized_start = 6085 - _ABCIMESSAGE_SNAPSHOT._serialized_end = 6175 - _ABCIMESSAGE_TIMESTAMP._serialized_start = 6177 - _ABCIMESSAGE_TIMESTAMP._serialized_end = 6220 - _ABCIMESSAGE_VALIDATORUPDATES._serialized_start = 6223 - _ABCIMESSAGE_VALIDATORUPDATES._serialized_end = 6506 - _ABCIMESSAGE_VALIDATORUPDATES_PUBLICKEY._serialized_start = 6333 - _ABCIMESSAGE_VALIDATORUPDATES_PUBLICKEY._serialized_end = 6391 - _ABCIMESSAGE_VALIDATORUPDATES_VALIDATORUPDATE._serialized_start = 6393 - _ABCIMESSAGE_VALIDATORUPDATES_VALIDATORUPDATE._serialized_end = 6506 - _ABCIMESSAGE_REQUEST_ECHO_PERFORMATIVE._serialized_start = 6508 - _ABCIMESSAGE_REQUEST_ECHO_PERFORMATIVE._serialized_end = 6552 - _ABCIMESSAGE_REQUEST_FLUSH_PERFORMATIVE._serialized_start = 6554 - _ABCIMESSAGE_REQUEST_FLUSH_PERFORMATIVE._serialized_end = 6582 - _ABCIMESSAGE_REQUEST_INFO_PERFORMATIVE._serialized_start = 6584 - _ABCIMESSAGE_REQUEST_INFO_PERFORMATIVE._serialized_end = 6672 - _ABCIMESSAGE_REQUEST_SET_OPTION_PERFORMATIVE._serialized_start = 6674 - _ABCIMESSAGE_REQUEST_SET_OPTION_PERFORMATIVE._serialized_end = 6749 - _ABCIMESSAGE_REQUEST_INIT_CHAIN_PERFORMATIVE._serialized_start = 6752 - _ABCIMESSAGE_REQUEST_INIT_CHAIN_PERFORMATIVE._serialized_end = 7099 - _ABCIMESSAGE_REQUEST_QUERY_PERFORMATIVE._serialized_start = 7101 - _ABCIMESSAGE_REQUEST_QUERY_PERFORMATIVE._serialized_end = 7194 - _ABCIMESSAGE_REQUEST_BEGIN_BLOCK_PERFORMATIVE._serialized_start = 7197 - _ABCIMESSAGE_REQUEST_BEGIN_BLOCK_PERFORMATIVE._serialized_end = 7460 - _ABCIMESSAGE_REQUEST_CHECK_TX_PERFORMATIVE._serialized_start = 7462 - _ABCIMESSAGE_REQUEST_CHECK_TX_PERFORMATIVE._serialized_end = 7568 - _ABCIMESSAGE_REQUEST_DELIVER_TX_PERFORMATIVE._serialized_start = 7570 - _ABCIMESSAGE_REQUEST_DELIVER_TX_PERFORMATIVE._serialized_end = 7615 - _ABCIMESSAGE_REQUEST_END_BLOCK_PERFORMATIVE._serialized_start = 7617 - _ABCIMESSAGE_REQUEST_END_BLOCK_PERFORMATIVE._serialized_end = 7665 - _ABCIMESSAGE_REQUEST_COMMIT_PERFORMATIVE._serialized_start = 7667 - _ABCIMESSAGE_REQUEST_COMMIT_PERFORMATIVE._serialized_end = 7696 - _ABCIMESSAGE_REQUEST_LIST_SNAPSHOTS_PERFORMATIVE._serialized_start = 7698 - _ABCIMESSAGE_REQUEST_LIST_SNAPSHOTS_PERFORMATIVE._serialized_end = 7735 - _ABCIMESSAGE_REQUEST_OFFER_SNAPSHOT_PERFORMATIVE._serialized_start = 7737 - _ABCIMESSAGE_REQUEST_OFFER_SNAPSHOT_PERFORMATIVE._serialized_end = 7856 - _ABCIMESSAGE_REQUEST_LOAD_SNAPSHOT_CHUNK_PERFORMATIVE._serialized_start = 7858 - _ABCIMESSAGE_REQUEST_LOAD_SNAPSHOT_CHUNK_PERFORMATIVE._serialized_end = 7953 - _ABCIMESSAGE_REQUEST_APPLY_SNAPSHOT_CHUNK_PERFORMATIVE._serialized_start = 7955 - _ABCIMESSAGE_REQUEST_APPLY_SNAPSHOT_CHUNK_PERFORMATIVE._serialized_end = 8050 - _ABCIMESSAGE_RESPONSE_EXCEPTION_PERFORMATIVE._serialized_start = 8052 - _ABCIMESSAGE_RESPONSE_EXCEPTION_PERFORMATIVE._serialized_end = 8100 - _ABCIMESSAGE_RESPONSE_ECHO_PERFORMATIVE._serialized_start = 8102 - _ABCIMESSAGE_RESPONSE_ECHO_PERFORMATIVE._serialized_end = 8147 - _ABCIMESSAGE_RESPONSE_FLUSH_PERFORMATIVE._serialized_start = 8149 - _ABCIMESSAGE_RESPONSE_FLUSH_PERFORMATIVE._serialized_end = 8178 - _ABCIMESSAGE_RESPONSE_INFO_PERFORMATIVE._serialized_start = 8181 - _ABCIMESSAGE_RESPONSE_INFO_PERFORMATIVE._serialized_end = 8322 - _ABCIMESSAGE_RESPONSE_SET_OPTION_PERFORMATIVE._serialized_start = 8324 - _ABCIMESSAGE_RESPONSE_SET_OPTION_PERFORMATIVE._serialized_end = 8399 - _ABCIMESSAGE_RESPONSE_INIT_CHAIN_PERFORMATIVE._serialized_start = 8402 - _ABCIMESSAGE_RESPONSE_INIT_CHAIN_PERFORMATIVE._serialized_end = 8640 - _ABCIMESSAGE_RESPONSE_QUERY_PERFORMATIVE._serialized_start = 8643 - _ABCIMESSAGE_RESPONSE_QUERY_PERFORMATIVE._serialized_end = 8856 - _ABCIMESSAGE_RESPONSE_BEGIN_BLOCK_PERFORMATIVE._serialized_start = 8858 - _ABCIMESSAGE_RESPONSE_BEGIN_BLOCK_PERFORMATIVE._serialized_end = 8953 - _ABCIMESSAGE_RESPONSE_CHECK_TX_PERFORMATIVE._serialized_start = 8956 - _ABCIMESSAGE_RESPONSE_CHECK_TX_PERFORMATIVE._serialized_end = 9160 - _ABCIMESSAGE_RESPONSE_DELIVER_TX_PERFORMATIVE._serialized_start = 9163 - _ABCIMESSAGE_RESPONSE_DELIVER_TX_PERFORMATIVE._serialized_end = 9369 - _ABCIMESSAGE_RESPONSE_END_BLOCK_PERFORMATIVE._serialized_start = 9372 - _ABCIMESSAGE_RESPONSE_END_BLOCK_PERFORMATIVE._serialized_end = 9672 - _ABCIMESSAGE_RESPONSE_COMMIT_PERFORMATIVE._serialized_start = 9674 - _ABCIMESSAGE_RESPONSE_COMMIT_PERFORMATIVE._serialized_end = 9741 - _ABCIMESSAGE_RESPONSE_LIST_SNAPSHOTS_PERFORMATIVE._serialized_start = 9743 - _ABCIMESSAGE_RESPONSE_LIST_SNAPSHOTS_PERFORMATIVE._serialized_end = 9847 - _ABCIMESSAGE_RESPONSE_OFFER_SNAPSHOT_PERFORMATIVE._serialized_start = 9849 - _ABCIMESSAGE_RESPONSE_OFFER_SNAPSHOT_PERFORMATIVE._serialized_end = 9947 - _ABCIMESSAGE_RESPONSE_LOAD_SNAPSHOT_CHUNK_PERFORMATIVE._serialized_start = 9949 - _ABCIMESSAGE_RESPONSE_LOAD_SNAPSHOT_CHUNK_PERFORMATIVE._serialized_end = 10007 - _ABCIMESSAGE_RESPONSE_APPLY_SNAPSHOT_CHUNK_PERFORMATIVE._serialized_start = 10010 - _ABCIMESSAGE_RESPONSE_APPLY_SNAPSHOT_CHUNK_PERFORMATIVE._serialized_end = 10162 - _ABCIMESSAGE_DUMMY_PERFORMATIVE._serialized_start = 10164 - _ABCIMESSAGE_DUMMY_PERFORMATIVE._serialized_end = 10269 + _globals["_ABCIMESSAGE"]._serialized_start = 39 + _globals["_ABCIMESSAGE"]._serialized_end = 10285 + _globals["_ABCIMESSAGE_CHECKTXTYPE"]._serialized_start = 3222 + _globals["_ABCIMESSAGE_CHECKTXTYPE"]._serialized_end = 3349 + _globals["_ABCIMESSAGE_CHECKTXTYPE__CHECKTXTYPE"]._serialized_start = 3313 + _globals["_ABCIMESSAGE_CHECKTXTYPE__CHECKTXTYPE"]._serialized_end = 3349 + _globals["_ABCIMESSAGE_CONSENSUSPARAMS"]._serialized_start = 3352 + _globals["_ABCIMESSAGE_CONSENSUSPARAMS"]._serialized_end = 4036 + _globals["_ABCIMESSAGE_CONSENSUSPARAMS_DURATION"]._serialized_start = 3709 + _globals["_ABCIMESSAGE_CONSENSUSPARAMS_DURATION"]._serialized_end = 3751 + _globals["_ABCIMESSAGE_CONSENSUSPARAMS_BLOCKPARAMS"]._serialized_start = 3753 + _globals["_ABCIMESSAGE_CONSENSUSPARAMS_BLOCKPARAMS"]._serialized_end = 3802 + _globals["_ABCIMESSAGE_CONSENSUSPARAMS_EVIDENCEPARAMS"]._serialized_start = 3805 + _globals["_ABCIMESSAGE_CONSENSUSPARAMS_EVIDENCEPARAMS"]._serialized_end = 3956 + _globals["_ABCIMESSAGE_CONSENSUSPARAMS_VALIDATORPARAMS"]._serialized_start = 3958 + _globals["_ABCIMESSAGE_CONSENSUSPARAMS_VALIDATORPARAMS"]._serialized_end = 3998 + _globals["_ABCIMESSAGE_CONSENSUSPARAMS_VERSIONPARAMS"]._serialized_start = 4000 + _globals["_ABCIMESSAGE_CONSENSUSPARAMS_VERSIONPARAMS"]._serialized_end = 4036 + _globals["_ABCIMESSAGE_EVENTS"]._serialized_start = 4039 + _globals["_ABCIMESSAGE_EVENTS"]._serialized_end = 4276 + _globals["_ABCIMESSAGE_EVENTS_EVENTATTRIBUTE"]._serialized_start = 4115 + _globals["_ABCIMESSAGE_EVENTS_EVENTATTRIBUTE"]._serialized_end = 4174 + _globals["_ABCIMESSAGE_EVENTS_EVENT"]._serialized_start = 4176 + _globals["_ABCIMESSAGE_EVENTS_EVENT"]._serialized_end = 4276 + _globals["_ABCIMESSAGE_EVIDENCES"]._serialized_start = 4279 + _globals["_ABCIMESSAGE_EVIDENCES"]._serialized_end = 4732 + _globals["_ABCIMESSAGE_EVIDENCES_EVIDENCE"]._serialized_start = 4379 + _globals["_ABCIMESSAGE_EVIDENCES_EVIDENCE"]._serialized_end = 4732 + _globals["_ABCIMESSAGE_EVIDENCES_EVIDENCE_EVIDENCETYPE"]._serialized_start = 4660 + _globals["_ABCIMESSAGE_EVIDENCES_EVIDENCE_EVIDENCETYPE"]._serialized_end = 4732 + _globals["_ABCIMESSAGE_HEADER"]._serialized_start = 4735 + _globals["_ABCIMESSAGE_HEADER"]._serialized_end = 5411 + _globals["_ABCIMESSAGE_HEADER_CONSENSUSVERSION"]._serialized_start = 5211 + _globals["_ABCIMESSAGE_HEADER_CONSENSUSVERSION"]._serialized_end = 5257 + _globals["_ABCIMESSAGE_HEADER_BLOCKID"]._serialized_start = 5259 + _globals["_ABCIMESSAGE_HEADER_BLOCKID"]._serialized_end = 5365 + _globals["_ABCIMESSAGE_HEADER_PARTSETHEADER"]._serialized_start = 5367 + _globals["_ABCIMESSAGE_HEADER_PARTSETHEADER"]._serialized_end = 5411 + _globals["_ABCIMESSAGE_LASTCOMMITINFO"]._serialized_start = 5414 + _globals["_ABCIMESSAGE_LASTCOMMITINFO"]._serialized_end = 5686 + _globals["_ABCIMESSAGE_LASTCOMMITINFO_VALIDATOR"]._serialized_start = 5523 + _globals["_ABCIMESSAGE_LASTCOMMITINFO_VALIDATOR"]._serialized_end = 5566 + _globals["_ABCIMESSAGE_LASTCOMMITINFO_VOTEINFO"]._serialized_start = 5568 + _globals["_ABCIMESSAGE_LASTCOMMITINFO_VOTEINFO"]._serialized_end = 5686 + _globals["_ABCIMESSAGE_PROOFOPS"]._serialized_start = 5689 + _globals["_ABCIMESSAGE_PROOFOPS"]._serialized_end = 5818 + _globals["_ABCIMESSAGE_PROOFOPS_PROOFOP"]._serialized_start = 5768 + _globals["_ABCIMESSAGE_PROOFOPS_PROOFOP"]._serialized_end = 5818 + _globals["_ABCIMESSAGE_RESULT"]._serialized_start = 5821 + _globals["_ABCIMESSAGE_RESULT"]._serialized_end = 6005 + _globals["_ABCIMESSAGE_RESULT_RESULTTYPE"]._serialized_start = 5907 + _globals["_ABCIMESSAGE_RESULT_RESULTTYPE"]._serialized_end = 6005 + _globals["_ABCIMESSAGE_SNAPSHOTS"]._serialized_start = 6007 + _globals["_ABCIMESSAGE_SNAPSHOTS"]._serialized_end = 6083 + _globals["_ABCIMESSAGE_SNAPSHOT"]._serialized_start = 6085 + _globals["_ABCIMESSAGE_SNAPSHOT"]._serialized_end = 6175 + _globals["_ABCIMESSAGE_TIMESTAMP"]._serialized_start = 6177 + _globals["_ABCIMESSAGE_TIMESTAMP"]._serialized_end = 6220 + _globals["_ABCIMESSAGE_VALIDATORUPDATES"]._serialized_start = 6223 + _globals["_ABCIMESSAGE_VALIDATORUPDATES"]._serialized_end = 6506 + _globals["_ABCIMESSAGE_VALIDATORUPDATES_PUBLICKEY"]._serialized_start = 6333 + _globals["_ABCIMESSAGE_VALIDATORUPDATES_PUBLICKEY"]._serialized_end = 6391 + _globals["_ABCIMESSAGE_VALIDATORUPDATES_VALIDATORUPDATE"]._serialized_start = 6393 + _globals["_ABCIMESSAGE_VALIDATORUPDATES_VALIDATORUPDATE"]._serialized_end = 6506 + _globals["_ABCIMESSAGE_REQUEST_ECHO_PERFORMATIVE"]._serialized_start = 6508 + _globals["_ABCIMESSAGE_REQUEST_ECHO_PERFORMATIVE"]._serialized_end = 6552 + _globals["_ABCIMESSAGE_REQUEST_FLUSH_PERFORMATIVE"]._serialized_start = 6554 + _globals["_ABCIMESSAGE_REQUEST_FLUSH_PERFORMATIVE"]._serialized_end = 6582 + _globals["_ABCIMESSAGE_REQUEST_INFO_PERFORMATIVE"]._serialized_start = 6584 + _globals["_ABCIMESSAGE_REQUEST_INFO_PERFORMATIVE"]._serialized_end = 6672 + _globals["_ABCIMESSAGE_REQUEST_SET_OPTION_PERFORMATIVE"]._serialized_start = 6674 + _globals["_ABCIMESSAGE_REQUEST_SET_OPTION_PERFORMATIVE"]._serialized_end = 6749 + _globals["_ABCIMESSAGE_REQUEST_INIT_CHAIN_PERFORMATIVE"]._serialized_start = 6752 + _globals["_ABCIMESSAGE_REQUEST_INIT_CHAIN_PERFORMATIVE"]._serialized_end = 7099 + _globals["_ABCIMESSAGE_REQUEST_QUERY_PERFORMATIVE"]._serialized_start = 7101 + _globals["_ABCIMESSAGE_REQUEST_QUERY_PERFORMATIVE"]._serialized_end = 7194 + _globals["_ABCIMESSAGE_REQUEST_BEGIN_BLOCK_PERFORMATIVE"]._serialized_start = 7197 + _globals["_ABCIMESSAGE_REQUEST_BEGIN_BLOCK_PERFORMATIVE"]._serialized_end = 7460 + _globals["_ABCIMESSAGE_REQUEST_CHECK_TX_PERFORMATIVE"]._serialized_start = 7462 + _globals["_ABCIMESSAGE_REQUEST_CHECK_TX_PERFORMATIVE"]._serialized_end = 7568 + _globals["_ABCIMESSAGE_REQUEST_DELIVER_TX_PERFORMATIVE"]._serialized_start = 7570 + _globals["_ABCIMESSAGE_REQUEST_DELIVER_TX_PERFORMATIVE"]._serialized_end = 7615 + _globals["_ABCIMESSAGE_REQUEST_END_BLOCK_PERFORMATIVE"]._serialized_start = 7617 + _globals["_ABCIMESSAGE_REQUEST_END_BLOCK_PERFORMATIVE"]._serialized_end = 7665 + _globals["_ABCIMESSAGE_REQUEST_COMMIT_PERFORMATIVE"]._serialized_start = 7667 + _globals["_ABCIMESSAGE_REQUEST_COMMIT_PERFORMATIVE"]._serialized_end = 7696 + _globals[ + "_ABCIMESSAGE_REQUEST_LIST_SNAPSHOTS_PERFORMATIVE" + ]._serialized_start = 7698 + _globals["_ABCIMESSAGE_REQUEST_LIST_SNAPSHOTS_PERFORMATIVE"]._serialized_end = 7735 + _globals[ + "_ABCIMESSAGE_REQUEST_OFFER_SNAPSHOT_PERFORMATIVE" + ]._serialized_start = 7737 + _globals["_ABCIMESSAGE_REQUEST_OFFER_SNAPSHOT_PERFORMATIVE"]._serialized_end = 7856 + _globals[ + "_ABCIMESSAGE_REQUEST_LOAD_SNAPSHOT_CHUNK_PERFORMATIVE" + ]._serialized_start = 7858 + _globals[ + "_ABCIMESSAGE_REQUEST_LOAD_SNAPSHOT_CHUNK_PERFORMATIVE" + ]._serialized_end = 7953 + _globals[ + "_ABCIMESSAGE_REQUEST_APPLY_SNAPSHOT_CHUNK_PERFORMATIVE" + ]._serialized_start = 7955 + _globals[ + "_ABCIMESSAGE_REQUEST_APPLY_SNAPSHOT_CHUNK_PERFORMATIVE" + ]._serialized_end = 8050 + _globals["_ABCIMESSAGE_RESPONSE_EXCEPTION_PERFORMATIVE"]._serialized_start = 8052 + _globals["_ABCIMESSAGE_RESPONSE_EXCEPTION_PERFORMATIVE"]._serialized_end = 8100 + _globals["_ABCIMESSAGE_RESPONSE_ECHO_PERFORMATIVE"]._serialized_start = 8102 + _globals["_ABCIMESSAGE_RESPONSE_ECHO_PERFORMATIVE"]._serialized_end = 8147 + _globals["_ABCIMESSAGE_RESPONSE_FLUSH_PERFORMATIVE"]._serialized_start = 8149 + _globals["_ABCIMESSAGE_RESPONSE_FLUSH_PERFORMATIVE"]._serialized_end = 8178 + _globals["_ABCIMESSAGE_RESPONSE_INFO_PERFORMATIVE"]._serialized_start = 8181 + _globals["_ABCIMESSAGE_RESPONSE_INFO_PERFORMATIVE"]._serialized_end = 8322 + _globals["_ABCIMESSAGE_RESPONSE_SET_OPTION_PERFORMATIVE"]._serialized_start = 8324 + _globals["_ABCIMESSAGE_RESPONSE_SET_OPTION_PERFORMATIVE"]._serialized_end = 8399 + _globals["_ABCIMESSAGE_RESPONSE_INIT_CHAIN_PERFORMATIVE"]._serialized_start = 8402 + _globals["_ABCIMESSAGE_RESPONSE_INIT_CHAIN_PERFORMATIVE"]._serialized_end = 8640 + _globals["_ABCIMESSAGE_RESPONSE_QUERY_PERFORMATIVE"]._serialized_start = 8643 + _globals["_ABCIMESSAGE_RESPONSE_QUERY_PERFORMATIVE"]._serialized_end = 8856 + _globals["_ABCIMESSAGE_RESPONSE_BEGIN_BLOCK_PERFORMATIVE"]._serialized_start = 8858 + _globals["_ABCIMESSAGE_RESPONSE_BEGIN_BLOCK_PERFORMATIVE"]._serialized_end = 8953 + _globals["_ABCIMESSAGE_RESPONSE_CHECK_TX_PERFORMATIVE"]._serialized_start = 8956 + _globals["_ABCIMESSAGE_RESPONSE_CHECK_TX_PERFORMATIVE"]._serialized_end = 9160 + _globals["_ABCIMESSAGE_RESPONSE_DELIVER_TX_PERFORMATIVE"]._serialized_start = 9163 + _globals["_ABCIMESSAGE_RESPONSE_DELIVER_TX_PERFORMATIVE"]._serialized_end = 9369 + _globals["_ABCIMESSAGE_RESPONSE_END_BLOCK_PERFORMATIVE"]._serialized_start = 9372 + _globals["_ABCIMESSAGE_RESPONSE_END_BLOCK_PERFORMATIVE"]._serialized_end = 9672 + _globals["_ABCIMESSAGE_RESPONSE_COMMIT_PERFORMATIVE"]._serialized_start = 9674 + _globals["_ABCIMESSAGE_RESPONSE_COMMIT_PERFORMATIVE"]._serialized_end = 9741 + _globals[ + "_ABCIMESSAGE_RESPONSE_LIST_SNAPSHOTS_PERFORMATIVE" + ]._serialized_start = 9743 + _globals["_ABCIMESSAGE_RESPONSE_LIST_SNAPSHOTS_PERFORMATIVE"]._serialized_end = 9847 + _globals[ + "_ABCIMESSAGE_RESPONSE_OFFER_SNAPSHOT_PERFORMATIVE" + ]._serialized_start = 9849 + _globals["_ABCIMESSAGE_RESPONSE_OFFER_SNAPSHOT_PERFORMATIVE"]._serialized_end = 9947 + _globals[ + "_ABCIMESSAGE_RESPONSE_LOAD_SNAPSHOT_CHUNK_PERFORMATIVE" + ]._serialized_start = 9949 + _globals[ + "_ABCIMESSAGE_RESPONSE_LOAD_SNAPSHOT_CHUNK_PERFORMATIVE" + ]._serialized_end = 10007 + _globals[ + "_ABCIMESSAGE_RESPONSE_APPLY_SNAPSHOT_CHUNK_PERFORMATIVE" + ]._serialized_start = 10010 + _globals[ + "_ABCIMESSAGE_RESPONSE_APPLY_SNAPSHOT_CHUNK_PERFORMATIVE" + ]._serialized_end = 10162 + _globals["_ABCIMESSAGE_DUMMY_PERFORMATIVE"]._serialized_start = 10164 + _globals["_ABCIMESSAGE_DUMMY_PERFORMATIVE"]._serialized_end = 10269 # @@protoc_insertion_point(module_scope) diff --git a/packages/valory/protocols/abci/message.py b/packages/valory/protocols/abci/message.py index 46d4634e92..69a18d72b2 100644 --- a/packages/valory/protocols/abci/message.py +++ b/packages/valory/protocols/abci/message.py @@ -25,7 +25,7 @@ from aea.configurations.base import PublicId from aea.exceptions import AEAEnforceError, enforce -from aea.protocols.base import Message +from aea.protocols.base import Message # type: ignore from packages.valory.protocols.abci.custom_types import CheckTxType as CustomCheckTxType from packages.valory.protocols.abci.custom_types import ( diff --git a/packages/valory/protocols/abci/protocol.yaml b/packages/valory/protocols/abci/protocol.yaml index 8bc06f344d..f9ae7be958 100644 --- a/packages/valory/protocols/abci/protocol.yaml +++ b/packages/valory/protocols/abci/protocol.yaml @@ -8,13 +8,13 @@ license: Apache-2.0 aea_version: '>=1.0.0, <2.0.0' fingerprint: README.md: bafybeia5y34dgznojhabsw7js2auxzmwxoubs2yacvscvoqkmt323d3npq - __init__.py: bafybeidyj3jxy544bgbo45v4tox4rz5msrqmwgnn26hbtoqoiwvvgwzf54 + __init__.py: bafybeiewslofryyx4w25plslmsfh3lhhwaqfr66rvsrerxyzf5nsa5zuqi abci.proto: bafybeid2kv4fy6xx453apqxashnqfjymhbrvtxj3uq2vdtqr45lvlfjzm4 - abci_pb2.py: bafybeihged4uxj35ilybe3jaephddceqrk4taztfq4ytyf7wgs4ve2u66e + abci_pb2.py: bafybeiamdsjnddab32gu3xxa2tj4hkuaor2aboqem5dpt4ug25hhejp2li custom_types.py: bafybeihpkluue4c7cunrcaxze3pqexhmwxkybrv4c3bzmkkakze7n6v44a dialogues.py: bafybeiatyk6bgdw36clk5q6pqzoow7owjppwgmjyn7ofamg5urcwdu7mqy - message.py: bafybeib3iyxwrkq3f3qpfhm6bsfhsjdkrnjfvyoeqg35s46h2uafvrlvxq - serialization.py: bafybeifralovb766v2sl5gmxaqr7xz7srbrzsixrr4nzseptkwgddph5e4 + message.py: bafybeihse4kojm26rplaufkswenbjldvchtwcrzvitobqbf3wfyszlp5gu + serialization.py: bafybeicj23iadpep3ewjomegc25rmqphw6v6v7ro3z7pesbojkpk2ohqfe tests/__init__.py: bafybeie4cd5xo7o4teyfjclaju3zoguuahjvkpsbshda3x23jcph53fdpi tests/conftest.py: bafybeidomydt6bdji22rndrdb5w773vvdja55o5m5n4pbfslx7ey5euot4 tests/test_abci.py: bafybeig4gex7e62uxca7riaetmr2pu5xekxg3d7xjvck72zjd3uxny4v64 diff --git a/packages/valory/protocols/abci/serialization.py b/packages/valory/protocols/abci/serialization.py index 6941f6052d..3e74acbef8 100644 --- a/packages/valory/protocols/abci/serialization.py +++ b/packages/valory/protocols/abci/serialization.py @@ -22,12 +22,13 @@ # pylint: disable=too-many-statements,too-many-locals,no-member,too-few-public-methods,redefined-builtin from typing import Any, Dict, cast -from aea.mail.base_pb2 import DialogueMessage -from aea.mail.base_pb2 import Message as ProtobufMessage -from aea.protocols.base import Message, Serializer +from aea.mail.base_pb2 import DialogueMessage # type: ignore +from aea.mail.base_pb2 import Message as ProtobufMessage # type: ignore +from aea.protocols.base import Message # type: ignore +from aea.protocols.base import Serializer # type: ignore -from packages.valory.protocols.abci import abci_pb2 -from packages.valory.protocols.abci.custom_types import ( +from packages.valory.protocols.abci import abci_pb2 # type: ignore +from packages.valory.protocols.abci.custom_types import ( # type: ignore CheckTxType, ConsensusParams, Events, @@ -41,7 +42,7 @@ Timestamp, ValidatorUpdates, ) -from packages.valory.protocols.abci.message import AbciMessage +from packages.valory.protocols.abci.message import AbciMessage # type: ignore class AbciSerializer(Serializer): @@ -58,7 +59,7 @@ def encode(msg: Message) -> bytes: msg = cast(AbciMessage, msg) message_pb = ProtobufMessage() dialogue_message_pb = DialogueMessage() - abci_msg = abci_pb2.AbciMessage() + abci_msg = abci_pb2.AbciMessage() # type: ignore dialogue_message_pb.message_id = msg.message_id dialogue_reference = msg.dialogue_reference @@ -357,7 +358,7 @@ def decode(obj: bytes) -> Message: :return: the 'Abci' message. """ message_pb = ProtobufMessage() - abci_pb = abci_pb2.AbciMessage() + abci_pb = abci_pb2.AbciMessage() # type: ignore message_pb.ParseFromString(obj) message_id = message_pb.dialogue_message.message_id dialogue_reference = ( diff --git a/packages/valory/protocols/ipfs/__init__.py b/packages/valory/protocols/ipfs/__init__.py index 5f60c5089f..4477e88f2d 100644 --- a/packages/valory/protocols/ipfs/__init__.py +++ b/packages/valory/protocols/ipfs/__init__.py @@ -20,7 +20,7 @@ """ This module contains the support resources for the ipfs protocol. -It was created with protocol buffer compiler version `libprotoc 3.19.4` and aea protocol generator version `1.0.0`. +It was created with protocol buffer compiler version `libprotoc 24.3` and aea protocol generator version `1.0.0`. """ from packages.valory.protocols.ipfs.message import IpfsMessage diff --git a/packages/valory/protocols/ipfs/ipfs_pb2.py b/packages/valory/protocols/ipfs/ipfs_pb2.py index db34a5d22b..c69233ef6d 100644 --- a/packages/valory/protocols/ipfs/ipfs_pb2.py +++ b/packages/valory/protocols/ipfs/ipfs_pb2.py @@ -4,9 +4,8 @@ """Generated protocol buffer code.""" from google.protobuf import descriptor as _descriptor from google.protobuf import descriptor_pool as _descriptor_pool -from google.protobuf import message as _message -from google.protobuf import reflection as _reflection from google.protobuf import symbol_database as _symbol_database +from google.protobuf.internal import builder as _builder # @@protoc_insertion_point(imports) @@ -18,131 +17,29 @@ b'\n\nipfs.proto\x12\x16\x61\x65\x61.valory.ipfs.v0_1_0"\xb2\x07\n\x0bIpfsMessage\x12G\n\x05\x65rror\x18\x05 \x01(\x0b\x32\x36.aea.valory.ipfs.v0_1_0.IpfsMessage.Error_PerformativeH\x00\x12G\n\x05\x66iles\x18\x06 \x01(\x0b\x32\x36.aea.valory.ipfs.v0_1_0.IpfsMessage.Files_PerformativeH\x00\x12O\n\tget_files\x18\x07 \x01(\x0b\x32:.aea.valory.ipfs.v0_1_0.IpfsMessage.Get_Files_PerformativeH\x00\x12O\n\tipfs_hash\x18\x08 \x01(\x0b\x32:.aea.valory.ipfs.v0_1_0.IpfsMessage.Ipfs_Hash_PerformativeH\x00\x12S\n\x0bstore_files\x18\t \x01(\x0b\x32<.aea.valory.ipfs.v0_1_0.IpfsMessage.Store_Files_PerformativeH\x00\x1a\xc9\x01\n\x18Store_Files_Performative\x12V\n\x05\x66iles\x18\x01 \x03(\x0b\x32G.aea.valory.ipfs.v0_1_0.IpfsMessage.Store_Files_Performative.FilesEntry\x12\x0f\n\x07timeout\x18\x02 \x01(\x01\x12\x16\n\x0etimeout_is_set\x18\x03 \x01(\x08\x1a,\n\nFilesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\x1a+\n\x16Ipfs_Hash_Performative\x12\x11\n\tipfs_hash\x18\x01 \x01(\t\x1aT\n\x16Get_Files_Performative\x12\x11\n\tipfs_hash\x18\x01 \x01(\t\x12\x0f\n\x07timeout\x18\x02 \x01(\x01\x12\x16\n\x0etimeout_is_set\x18\x03 \x01(\x08\x1a\x94\x01\n\x12\x46iles_Performative\x12P\n\x05\x66iles\x18\x01 \x03(\x0b\x32\x41.aea.valory.ipfs.v0_1_0.IpfsMessage.Files_Performative.FilesEntry\x1a,\n\nFilesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\x1a$\n\x12\x45rror_Performative\x12\x0e\n\x06reason\x18\x01 \x01(\tB\x0e\n\x0cperformativeb\x06proto3' ) - -_IPFSMESSAGE = DESCRIPTOR.message_types_by_name["IpfsMessage"] -_IPFSMESSAGE_STORE_FILES_PERFORMATIVE = _IPFSMESSAGE.nested_types_by_name[ - "Store_Files_Performative" -] -_IPFSMESSAGE_STORE_FILES_PERFORMATIVE_FILESENTRY = ( - _IPFSMESSAGE_STORE_FILES_PERFORMATIVE.nested_types_by_name["FilesEntry"] -) -_IPFSMESSAGE_IPFS_HASH_PERFORMATIVE = _IPFSMESSAGE.nested_types_by_name[ - "Ipfs_Hash_Performative" -] -_IPFSMESSAGE_GET_FILES_PERFORMATIVE = _IPFSMESSAGE.nested_types_by_name[ - "Get_Files_Performative" -] -_IPFSMESSAGE_FILES_PERFORMATIVE = _IPFSMESSAGE.nested_types_by_name[ - "Files_Performative" -] -_IPFSMESSAGE_FILES_PERFORMATIVE_FILESENTRY = ( - _IPFSMESSAGE_FILES_PERFORMATIVE.nested_types_by_name["FilesEntry"] -) -_IPFSMESSAGE_ERROR_PERFORMATIVE = _IPFSMESSAGE.nested_types_by_name[ - "Error_Performative" -] -IpfsMessage = _reflection.GeneratedProtocolMessageType( - "IpfsMessage", - (_message.Message,), - { - "Store_Files_Performative": _reflection.GeneratedProtocolMessageType( - "Store_Files_Performative", - (_message.Message,), - { - "FilesEntry": _reflection.GeneratedProtocolMessageType( - "FilesEntry", - (_message.Message,), - { - "DESCRIPTOR": _IPFSMESSAGE_STORE_FILES_PERFORMATIVE_FILESENTRY, - "__module__": "ipfs_pb2" - # @@protoc_insertion_point(class_scope:aea.valory.ipfs.v0_1_0.IpfsMessage.Store_Files_Performative.FilesEntry) - }, - ), - "DESCRIPTOR": _IPFSMESSAGE_STORE_FILES_PERFORMATIVE, - "__module__": "ipfs_pb2" - # @@protoc_insertion_point(class_scope:aea.valory.ipfs.v0_1_0.IpfsMessage.Store_Files_Performative) - }, - ), - "Ipfs_Hash_Performative": _reflection.GeneratedProtocolMessageType( - "Ipfs_Hash_Performative", - (_message.Message,), - { - "DESCRIPTOR": _IPFSMESSAGE_IPFS_HASH_PERFORMATIVE, - "__module__": "ipfs_pb2" - # @@protoc_insertion_point(class_scope:aea.valory.ipfs.v0_1_0.IpfsMessage.Ipfs_Hash_Performative) - }, - ), - "Get_Files_Performative": _reflection.GeneratedProtocolMessageType( - "Get_Files_Performative", - (_message.Message,), - { - "DESCRIPTOR": _IPFSMESSAGE_GET_FILES_PERFORMATIVE, - "__module__": "ipfs_pb2" - # @@protoc_insertion_point(class_scope:aea.valory.ipfs.v0_1_0.IpfsMessage.Get_Files_Performative) - }, - ), - "Files_Performative": _reflection.GeneratedProtocolMessageType( - "Files_Performative", - (_message.Message,), - { - "FilesEntry": _reflection.GeneratedProtocolMessageType( - "FilesEntry", - (_message.Message,), - { - "DESCRIPTOR": _IPFSMESSAGE_FILES_PERFORMATIVE_FILESENTRY, - "__module__": "ipfs_pb2" - # @@protoc_insertion_point(class_scope:aea.valory.ipfs.v0_1_0.IpfsMessage.Files_Performative.FilesEntry) - }, - ), - "DESCRIPTOR": _IPFSMESSAGE_FILES_PERFORMATIVE, - "__module__": "ipfs_pb2" - # @@protoc_insertion_point(class_scope:aea.valory.ipfs.v0_1_0.IpfsMessage.Files_Performative) - }, - ), - "Error_Performative": _reflection.GeneratedProtocolMessageType( - "Error_Performative", - (_message.Message,), - { - "DESCRIPTOR": _IPFSMESSAGE_ERROR_PERFORMATIVE, - "__module__": "ipfs_pb2" - # @@protoc_insertion_point(class_scope:aea.valory.ipfs.v0_1_0.IpfsMessage.Error_Performative) - }, - ), - "DESCRIPTOR": _IPFSMESSAGE, - "__module__": "ipfs_pb2" - # @@protoc_insertion_point(class_scope:aea.valory.ipfs.v0_1_0.IpfsMessage) - }, -) -_sym_db.RegisterMessage(IpfsMessage) -_sym_db.RegisterMessage(IpfsMessage.Store_Files_Performative) -_sym_db.RegisterMessage(IpfsMessage.Store_Files_Performative.FilesEntry) -_sym_db.RegisterMessage(IpfsMessage.Ipfs_Hash_Performative) -_sym_db.RegisterMessage(IpfsMessage.Get_Files_Performative) -_sym_db.RegisterMessage(IpfsMessage.Files_Performative) -_sym_db.RegisterMessage(IpfsMessage.Files_Performative.FilesEntry) -_sym_db.RegisterMessage(IpfsMessage.Error_Performative) - +_globals = globals() +_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) +_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, "ipfs_pb2", _globals) if _descriptor._USE_C_DESCRIPTORS == False: - DESCRIPTOR._options = None _IPFSMESSAGE_STORE_FILES_PERFORMATIVE_FILESENTRY._options = None _IPFSMESSAGE_STORE_FILES_PERFORMATIVE_FILESENTRY._serialized_options = b"8\001" _IPFSMESSAGE_FILES_PERFORMATIVE_FILESENTRY._options = None _IPFSMESSAGE_FILES_PERFORMATIVE_FILESENTRY._serialized_options = b"8\001" - _IPFSMESSAGE._serialized_start = 39 - _IPFSMESSAGE._serialized_end = 985 - _IPFSMESSAGE_STORE_FILES_PERFORMATIVE._serialized_start = 448 - _IPFSMESSAGE_STORE_FILES_PERFORMATIVE._serialized_end = 649 - _IPFSMESSAGE_STORE_FILES_PERFORMATIVE_FILESENTRY._serialized_start = 605 - _IPFSMESSAGE_STORE_FILES_PERFORMATIVE_FILESENTRY._serialized_end = 649 - _IPFSMESSAGE_IPFS_HASH_PERFORMATIVE._serialized_start = 651 - _IPFSMESSAGE_IPFS_HASH_PERFORMATIVE._serialized_end = 694 - _IPFSMESSAGE_GET_FILES_PERFORMATIVE._serialized_start = 696 - _IPFSMESSAGE_GET_FILES_PERFORMATIVE._serialized_end = 780 - _IPFSMESSAGE_FILES_PERFORMATIVE._serialized_start = 783 - _IPFSMESSAGE_FILES_PERFORMATIVE._serialized_end = 931 - _IPFSMESSAGE_FILES_PERFORMATIVE_FILESENTRY._serialized_start = 605 - _IPFSMESSAGE_FILES_PERFORMATIVE_FILESENTRY._serialized_end = 649 - _IPFSMESSAGE_ERROR_PERFORMATIVE._serialized_start = 933 - _IPFSMESSAGE_ERROR_PERFORMATIVE._serialized_end = 969 + _globals["_IPFSMESSAGE"]._serialized_start = 39 + _globals["_IPFSMESSAGE"]._serialized_end = 985 + _globals["_IPFSMESSAGE_STORE_FILES_PERFORMATIVE"]._serialized_start = 448 + _globals["_IPFSMESSAGE_STORE_FILES_PERFORMATIVE"]._serialized_end = 649 + _globals["_IPFSMESSAGE_STORE_FILES_PERFORMATIVE_FILESENTRY"]._serialized_start = 605 + _globals["_IPFSMESSAGE_STORE_FILES_PERFORMATIVE_FILESENTRY"]._serialized_end = 649 + _globals["_IPFSMESSAGE_IPFS_HASH_PERFORMATIVE"]._serialized_start = 651 + _globals["_IPFSMESSAGE_IPFS_HASH_PERFORMATIVE"]._serialized_end = 694 + _globals["_IPFSMESSAGE_GET_FILES_PERFORMATIVE"]._serialized_start = 696 + _globals["_IPFSMESSAGE_GET_FILES_PERFORMATIVE"]._serialized_end = 780 + _globals["_IPFSMESSAGE_FILES_PERFORMATIVE"]._serialized_start = 783 + _globals["_IPFSMESSAGE_FILES_PERFORMATIVE"]._serialized_end = 931 + _globals["_IPFSMESSAGE_FILES_PERFORMATIVE_FILESENTRY"]._serialized_start = 605 + _globals["_IPFSMESSAGE_FILES_PERFORMATIVE_FILESENTRY"]._serialized_end = 649 + _globals["_IPFSMESSAGE_ERROR_PERFORMATIVE"]._serialized_start = 933 + _globals["_IPFSMESSAGE_ERROR_PERFORMATIVE"]._serialized_end = 969 # @@protoc_insertion_point(module_scope) diff --git a/packages/valory/protocols/ipfs/message.py b/packages/valory/protocols/ipfs/message.py index 9aa3be0de1..3a88fc8bdb 100644 --- a/packages/valory/protocols/ipfs/message.py +++ b/packages/valory/protocols/ipfs/message.py @@ -25,7 +25,7 @@ from aea.configurations.base import PublicId from aea.exceptions import AEAEnforceError, enforce -from aea.protocols.base import Message +from aea.protocols.base import Message # type: ignore _default_logger = logging.getLogger("aea.packages.valory.protocols.ipfs.message") diff --git a/packages/valory/protocols/ipfs/protocol.yaml b/packages/valory/protocols/ipfs/protocol.yaml index a731e2a426..cae27ded99 100644 --- a/packages/valory/protocols/ipfs/protocol.yaml +++ b/packages/valory/protocols/ipfs/protocol.yaml @@ -8,12 +8,12 @@ license: Apache-2.0 aea_version: '>=1.0.0, <2.0.0' fingerprint: README.md: bafybeidv64ed7ljvsggruwj3onb7dj7b5nyx4ngohacztdreujjztsuns4 - __init__.py: bafybeibxzovsffa3l2ac5h7yrhmbq2oplsteqtlhsgzvu2wvx7qvkyrkle + __init__.py: bafybeigtro2qlct3wc6dhtshv4sbh2myabruyb3mhadbcif46waylhtpga dialogues.py: bafybeihlnjaqvq5765hqttoqe3aeql572veyfbawsrcyko4wvds5wv7gwe ipfs.proto: bafybeifpe6szd3m2zjlvn5zwiy7mbimur7pu46lobxvyyarozabxpmhcs4 - ipfs_pb2.py: bafybeiaulqlxfb5uxthorlasrdrqjgt7obxpwzqfioswqsqmyxp4npjjze - message.py: bafybeihufe4v6jlwrzz5doeesr3tdsjgksi2shymrcdngfhmi3h6rsqoie - serialization.py: bafybeifi5snrp4knrxwftskyjb5zuipjfqeipqw6nxn4mbk42vdwkstxd4 + ipfs_pb2.py: bafybeihzspjtj2zoy3owb5itbz2lrintf7odanhvsi4qooxuqxu3ar6qpu + message.py: bafybeiaxoans2zu6g4zjmkoqmv4vck2t5ftwn74cejuds3ll5z7tno22dm + serialization.py: bafybeib54rauxqkzaaudz22fbiotryc7cg2i3r7x5qtw6eoui6sw26kt7e tests/test_ipfs_dialogues.py: bafybeigqi2cal5m252qf3ry75mldfd5kyqj3bgstvyzpjgpjgxhi2otpoa tests/test_ipfs_messages.py: bafybeiasgajluoijzuln3s4gcbv5xenzazejt5kgbs54momozsntzrudw4 fingerprint_ignore_patterns: [] diff --git a/packages/valory/protocols/ipfs/serialization.py b/packages/valory/protocols/ipfs/serialization.py index f85d753441..6d8dabe94b 100644 --- a/packages/valory/protocols/ipfs/serialization.py +++ b/packages/valory/protocols/ipfs/serialization.py @@ -22,12 +22,13 @@ # pylint: disable=too-many-statements,too-many-locals,no-member,too-few-public-methods,redefined-builtin from typing import Any, Dict, cast -from aea.mail.base_pb2 import DialogueMessage -from aea.mail.base_pb2 import Message as ProtobufMessage -from aea.protocols.base import Message, Serializer +from aea.mail.base_pb2 import DialogueMessage # type: ignore +from aea.mail.base_pb2 import Message as ProtobufMessage # type: ignore +from aea.protocols.base import Message # type: ignore +from aea.protocols.base import Serializer # type: ignore -from packages.valory.protocols.ipfs import ipfs_pb2 -from packages.valory.protocols.ipfs.message import IpfsMessage +from packages.valory.protocols.ipfs import ipfs_pb2 # type: ignore +from packages.valory.protocols.ipfs.message import IpfsMessage # type: ignore class IpfsSerializer(Serializer): @@ -44,7 +45,7 @@ def encode(msg: Message) -> bytes: msg = cast(IpfsMessage, msg) message_pb = ProtobufMessage() dialogue_message_pb = DialogueMessage() - ipfs_msg = ipfs_pb2.IpfsMessage() + ipfs_msg = ipfs_pb2.IpfsMessage() # type: ignore dialogue_message_pb.message_id = msg.message_id dialogue_reference = msg.dialogue_reference @@ -104,7 +105,7 @@ def decode(obj: bytes) -> Message: :return: the 'Ipfs' message. """ message_pb = ProtobufMessage() - ipfs_pb = ipfs_pb2.IpfsMessage() + ipfs_pb = ipfs_pb2.IpfsMessage() # type: ignore message_pb.ParseFromString(obj) message_id = message_pb.dialogue_message.message_id dialogue_reference = ( diff --git a/packages/valory/protocols/tendermint/__init__.py b/packages/valory/protocols/tendermint/__init__.py index 9d03351edc..6d3b64870a 100644 --- a/packages/valory/protocols/tendermint/__init__.py +++ b/packages/valory/protocols/tendermint/__init__.py @@ -20,7 +20,7 @@ """ This module contains the support resources for the tendermint protocol. -It was created with protocol buffer compiler version `libprotoc 3.19.4` and aea protocol generator version `1.0.0`. +It was created with protocol buffer compiler version `libprotoc 24.3` and aea protocol generator version `1.0.0`. """ from packages.valory.protocols.tendermint.message import TendermintMessage diff --git a/packages/valory/protocols/tendermint/message.py b/packages/valory/protocols/tendermint/message.py index cd6f31b927..0cdb5bf7c2 100644 --- a/packages/valory/protocols/tendermint/message.py +++ b/packages/valory/protocols/tendermint/message.py @@ -25,7 +25,7 @@ from aea.configurations.base import PublicId from aea.exceptions import AEAEnforceError, enforce -from aea.protocols.base import Message +from aea.protocols.base import Message # type: ignore from packages.valory.protocols.tendermint.custom_types import ( ErrorCode as CustomErrorCode, diff --git a/packages/valory/protocols/tendermint/protocol.yaml b/packages/valory/protocols/tendermint/protocol.yaml index e33dbb3245..264e5aedf5 100644 --- a/packages/valory/protocols/tendermint/protocol.yaml +++ b/packages/valory/protocols/tendermint/protocol.yaml @@ -9,13 +9,13 @@ license: Apache-2.0 aea_version: '>=1.0.0, <2.0.0' fingerprint: README.md: bafybeib23wtp5el2lu4vpq3uap7jiyhm5fmoofvv4sz54cvvqq6vsksra4 - __init__.py: bafybeibwqsohi3r243hocfaxlz7wjwk6pk6g5txfbty6jvol6itvnmzrxa + __init__.py: bafybeiboctjqylfltatp4vxvpzstbs6ytf5laadjzl76a2jszo6e4srntm custom_types.py: bafybeidbqm4h4fv24o3w6ueu4o3lyn5yaleyukahq7suvk6m2b6ydw4w3a dialogues.py: bafybeigtyur7v4dits7de37fx3xcgnlqaimbuzt3wehxt4vjmq3kowfnu4 - message.py: bafybeifosu5ckcnivuotfwsumly7mdjanwv7ia3z5rnmee7kqigtd7smo4 - serialization.py: bafybeif6erxpnajwu3mljxfwapdtqv6liknit3ykm5rrbx4uzq3w2cd3su + message.py: bafybeifdxejproeoci3movs3mb5dtnzxrqhqbz5so5buxittjnd5rwqlhi + serialization.py: bafybeifg26azix4i6dkhob3dfkc6rbgsftdt2issa753qdjzvnoqxldb4u tendermint.proto: bafybeiaqoltnijwje7iog7s3r4nbtly6rbfp6zwb2btnrw7xuenoxtobui - tendermint_pb2.py: bafybeihfddkaapcyprghywav46cunh56q7ecgq4f2de5qcozdxd7nqtr54 + tendermint_pb2.py: bafybeiay3q3pcvlitnhifh63vqkzvdyu4ywbbwj6vnoe5omqxmxg6gu25a tests/__init__.py: bafybeiguds53xs5tmygjd26a7xxilzdrgi2x262relfagdlvdzymacumie tests/test_tendermint.py: bafybeihnjxpkvgsclevn4bwi4qepw56vz554wox7gmhnjwobelbee7xpce tests/test_tendermint_dialogues.py: bafybeieoviq62cv62h4nglyr7qflzb32bjcvjbepmytgfpycuypnz3mriy diff --git a/packages/valory/protocols/tendermint/serialization.py b/packages/valory/protocols/tendermint/serialization.py index 3a10618e7c..89f8368edd 100644 --- a/packages/valory/protocols/tendermint/serialization.py +++ b/packages/valory/protocols/tendermint/serialization.py @@ -22,13 +22,16 @@ # pylint: disable=too-many-statements,too-many-locals,no-member,too-few-public-methods,redefined-builtin from typing import Any, Dict, cast -from aea.mail.base_pb2 import DialogueMessage -from aea.mail.base_pb2 import Message as ProtobufMessage -from aea.protocols.base import Message, Serializer +from aea.mail.base_pb2 import DialogueMessage # type: ignore +from aea.mail.base_pb2 import Message as ProtobufMessage # type: ignore +from aea.protocols.base import Message # type: ignore +from aea.protocols.base import Serializer # type: ignore -from packages.valory.protocols.tendermint import tendermint_pb2 -from packages.valory.protocols.tendermint.custom_types import ErrorCode -from packages.valory.protocols.tendermint.message import TendermintMessage +from packages.valory.protocols.tendermint import tendermint_pb2 # type: ignore +from packages.valory.protocols.tendermint.custom_types import ErrorCode # type: ignore +from packages.valory.protocols.tendermint.message import ( # type: ignore + TendermintMessage, +) class TendermintSerializer(Serializer): @@ -45,7 +48,7 @@ def encode(msg: Message) -> bytes: msg = cast(TendermintMessage, msg) message_pb = ProtobufMessage() dialogue_message_pb = DialogueMessage() - tendermint_msg = tendermint_pb2.TendermintMessage() + tendermint_msg = tendermint_pb2.TendermintMessage() # type: ignore dialogue_message_pb.message_id = msg.message_id dialogue_reference = msg.dialogue_reference @@ -105,7 +108,7 @@ def decode(obj: bytes) -> Message: :return: the 'Tendermint' message. """ message_pb = ProtobufMessage() - tendermint_pb = tendermint_pb2.TendermintMessage() + tendermint_pb = tendermint_pb2.TendermintMessage() # type: ignore message_pb.ParseFromString(obj) message_id = message_pb.dialogue_message.message_id dialogue_reference = ( diff --git a/packages/valory/protocols/tendermint/tendermint_pb2.py b/packages/valory/protocols/tendermint/tendermint_pb2.py index 4def2c8abe..aa4355b03d 100644 --- a/packages/valory/protocols/tendermint/tendermint_pb2.py +++ b/packages/valory/protocols/tendermint/tendermint_pb2.py @@ -4,9 +4,8 @@ """Generated protocol buffer code.""" from google.protobuf import descriptor as _descriptor from google.protobuf import descriptor_pool as _descriptor_pool -from google.protobuf import message as _message -from google.protobuf import reflection as _reflection from google.protobuf import symbol_database as _symbol_database +from google.protobuf.internal import builder as _builder # @@protoc_insertion_point(imports) @@ -18,132 +17,37 @@ b'\n\x10tendermint.proto\x12\x1c\x61\x65\x61.valory.tendermint.v0_1_0"\xad\t\n\x11TendermintMessage\x12S\n\x05\x65rror\x18\x05 \x01(\x0b\x32\x42.aea.valory.tendermint.v0_1_0.TendermintMessage.Error_PerformativeH\x00\x12\x61\n\x0cgenesis_info\x18\x06 \x01(\x0b\x32I.aea.valory.tendermint.v0_1_0.TendermintMessage.Genesis_Info_PerformativeH\x00\x12i\n\x10get_genesis_info\x18\x07 \x01(\x0b\x32M.aea.valory.tendermint.v0_1_0.TendermintMessage.Get_Genesis_Info_PerformativeH\x00\x12o\n\x13get_recovery_params\x18\x08 \x01(\x0b\x32P.aea.valory.tendermint.v0_1_0.TendermintMessage.Get_Recovery_Params_PerformativeH\x00\x12g\n\x0frecovery_params\x18\t \x01(\x0b\x32L.aea.valory.tendermint.v0_1_0.TendermintMessage.Recovery_Params_PerformativeH\x00\x1a\x8e\x01\n\tErrorCode\x12[\n\nerror_code\x18\x01 \x01(\x0e\x32G.aea.valory.tendermint.v0_1_0.TendermintMessage.ErrorCode.ErrorCodeEnum"$\n\rErrorCodeEnum\x12\x13\n\x0fINVALID_REQUEST\x10\x00\x1a\x44\n\x1dGet_Genesis_Info_Performative\x12\r\n\x05query\x18\x01 \x01(\t\x12\x14\n\x0cquery_is_set\x18\x02 \x01(\x08\x1aG\n Get_Recovery_Params_Performative\x12\r\n\x05query\x18\x01 \x01(\t\x12\x14\n\x0cquery_is_set\x18\x02 \x01(\x08\x1a)\n\x19Genesis_Info_Performative\x12\x0c\n\x04info\x18\x01 \x01(\t\x1a.\n\x1cRecovery_Params_Performative\x12\x0e\n\x06params\x18\x01 \x01(\t\x1a\x8f\x02\n\x12\x45rror_Performative\x12M\n\nerror_code\x18\x01 \x01(\x0b\x32\x39.aea.valory.tendermint.v0_1_0.TendermintMessage.ErrorCode\x12\x11\n\terror_msg\x18\x02 \x01(\t\x12\x65\n\nerror_data\x18\x03 \x03(\x0b\x32Q.aea.valory.tendermint.v0_1_0.TendermintMessage.Error_Performative.ErrorDataEntry\x1a\x30\n\x0e\x45rrorDataEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\x42\x0e\n\x0cperformativeb\x06proto3' ) - -_TENDERMINTMESSAGE = DESCRIPTOR.message_types_by_name["TendermintMessage"] -_TENDERMINTMESSAGE_ERRORCODE = _TENDERMINTMESSAGE.nested_types_by_name["ErrorCode"] -_TENDERMINTMESSAGE_GET_GENESIS_INFO_PERFORMATIVE = ( - _TENDERMINTMESSAGE.nested_types_by_name["Get_Genesis_Info_Performative"] -) -_TENDERMINTMESSAGE_GET_RECOVERY_PARAMS_PERFORMATIVE = ( - _TENDERMINTMESSAGE.nested_types_by_name["Get_Recovery_Params_Performative"] -) -_TENDERMINTMESSAGE_GENESIS_INFO_PERFORMATIVE = _TENDERMINTMESSAGE.nested_types_by_name[ - "Genesis_Info_Performative" -] -_TENDERMINTMESSAGE_RECOVERY_PARAMS_PERFORMATIVE = ( - _TENDERMINTMESSAGE.nested_types_by_name["Recovery_Params_Performative"] -) -_TENDERMINTMESSAGE_ERROR_PERFORMATIVE = _TENDERMINTMESSAGE.nested_types_by_name[ - "Error_Performative" -] -_TENDERMINTMESSAGE_ERROR_PERFORMATIVE_ERRORDATAENTRY = ( - _TENDERMINTMESSAGE_ERROR_PERFORMATIVE.nested_types_by_name["ErrorDataEntry"] -) -_TENDERMINTMESSAGE_ERRORCODE_ERRORCODEENUM = ( - _TENDERMINTMESSAGE_ERRORCODE.enum_types_by_name["ErrorCodeEnum"] -) -TendermintMessage = _reflection.GeneratedProtocolMessageType( - "TendermintMessage", - (_message.Message,), - { - "ErrorCode": _reflection.GeneratedProtocolMessageType( - "ErrorCode", - (_message.Message,), - { - "DESCRIPTOR": _TENDERMINTMESSAGE_ERRORCODE, - "__module__": "tendermint_pb2" - # @@protoc_insertion_point(class_scope:aea.valory.tendermint.v0_1_0.TendermintMessage.ErrorCode) - }, - ), - "Get_Genesis_Info_Performative": _reflection.GeneratedProtocolMessageType( - "Get_Genesis_Info_Performative", - (_message.Message,), - { - "DESCRIPTOR": _TENDERMINTMESSAGE_GET_GENESIS_INFO_PERFORMATIVE, - "__module__": "tendermint_pb2" - # @@protoc_insertion_point(class_scope:aea.valory.tendermint.v0_1_0.TendermintMessage.Get_Genesis_Info_Performative) - }, - ), - "Get_Recovery_Params_Performative": _reflection.GeneratedProtocolMessageType( - "Get_Recovery_Params_Performative", - (_message.Message,), - { - "DESCRIPTOR": _TENDERMINTMESSAGE_GET_RECOVERY_PARAMS_PERFORMATIVE, - "__module__": "tendermint_pb2" - # @@protoc_insertion_point(class_scope:aea.valory.tendermint.v0_1_0.TendermintMessage.Get_Recovery_Params_Performative) - }, - ), - "Genesis_Info_Performative": _reflection.GeneratedProtocolMessageType( - "Genesis_Info_Performative", - (_message.Message,), - { - "DESCRIPTOR": _TENDERMINTMESSAGE_GENESIS_INFO_PERFORMATIVE, - "__module__": "tendermint_pb2" - # @@protoc_insertion_point(class_scope:aea.valory.tendermint.v0_1_0.TendermintMessage.Genesis_Info_Performative) - }, - ), - "Recovery_Params_Performative": _reflection.GeneratedProtocolMessageType( - "Recovery_Params_Performative", - (_message.Message,), - { - "DESCRIPTOR": _TENDERMINTMESSAGE_RECOVERY_PARAMS_PERFORMATIVE, - "__module__": "tendermint_pb2" - # @@protoc_insertion_point(class_scope:aea.valory.tendermint.v0_1_0.TendermintMessage.Recovery_Params_Performative) - }, - ), - "Error_Performative": _reflection.GeneratedProtocolMessageType( - "Error_Performative", - (_message.Message,), - { - "ErrorDataEntry": _reflection.GeneratedProtocolMessageType( - "ErrorDataEntry", - (_message.Message,), - { - "DESCRIPTOR": _TENDERMINTMESSAGE_ERROR_PERFORMATIVE_ERRORDATAENTRY, - "__module__": "tendermint_pb2" - # @@protoc_insertion_point(class_scope:aea.valory.tendermint.v0_1_0.TendermintMessage.Error_Performative.ErrorDataEntry) - }, - ), - "DESCRIPTOR": _TENDERMINTMESSAGE_ERROR_PERFORMATIVE, - "__module__": "tendermint_pb2" - # @@protoc_insertion_point(class_scope:aea.valory.tendermint.v0_1_0.TendermintMessage.Error_Performative) - }, - ), - "DESCRIPTOR": _TENDERMINTMESSAGE, - "__module__": "tendermint_pb2" - # @@protoc_insertion_point(class_scope:aea.valory.tendermint.v0_1_0.TendermintMessage) - }, -) -_sym_db.RegisterMessage(TendermintMessage) -_sym_db.RegisterMessage(TendermintMessage.ErrorCode) -_sym_db.RegisterMessage(TendermintMessage.Get_Genesis_Info_Performative) -_sym_db.RegisterMessage(TendermintMessage.Get_Recovery_Params_Performative) -_sym_db.RegisterMessage(TendermintMessage.Genesis_Info_Performative) -_sym_db.RegisterMessage(TendermintMessage.Recovery_Params_Performative) -_sym_db.RegisterMessage(TendermintMessage.Error_Performative) -_sym_db.RegisterMessage(TendermintMessage.Error_Performative.ErrorDataEntry) - +_globals = globals() +_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) +_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, "tendermint_pb2", _globals) if _descriptor._USE_C_DESCRIPTORS == False: - DESCRIPTOR._options = None _TENDERMINTMESSAGE_ERROR_PERFORMATIVE_ERRORDATAENTRY._options = None _TENDERMINTMESSAGE_ERROR_PERFORMATIVE_ERRORDATAENTRY._serialized_options = b"8\001" - _TENDERMINTMESSAGE._serialized_start = 51 - _TENDERMINTMESSAGE._serialized_end = 1248 - _TENDERMINTMESSAGE_ERRORCODE._serialized_start = 582 - _TENDERMINTMESSAGE_ERRORCODE._serialized_end = 724 - _TENDERMINTMESSAGE_ERRORCODE_ERRORCODEENUM._serialized_start = 688 - _TENDERMINTMESSAGE_ERRORCODE_ERRORCODEENUM._serialized_end = 724 - _TENDERMINTMESSAGE_GET_GENESIS_INFO_PERFORMATIVE._serialized_start = 726 - _TENDERMINTMESSAGE_GET_GENESIS_INFO_PERFORMATIVE._serialized_end = 794 - _TENDERMINTMESSAGE_GET_RECOVERY_PARAMS_PERFORMATIVE._serialized_start = 796 - _TENDERMINTMESSAGE_GET_RECOVERY_PARAMS_PERFORMATIVE._serialized_end = 867 - _TENDERMINTMESSAGE_GENESIS_INFO_PERFORMATIVE._serialized_start = 869 - _TENDERMINTMESSAGE_GENESIS_INFO_PERFORMATIVE._serialized_end = 910 - _TENDERMINTMESSAGE_RECOVERY_PARAMS_PERFORMATIVE._serialized_start = 912 - _TENDERMINTMESSAGE_RECOVERY_PARAMS_PERFORMATIVE._serialized_end = 958 - _TENDERMINTMESSAGE_ERROR_PERFORMATIVE._serialized_start = 961 - _TENDERMINTMESSAGE_ERROR_PERFORMATIVE._serialized_end = 1232 - _TENDERMINTMESSAGE_ERROR_PERFORMATIVE_ERRORDATAENTRY._serialized_start = 1184 - _TENDERMINTMESSAGE_ERROR_PERFORMATIVE_ERRORDATAENTRY._serialized_end = 1232 + _globals["_TENDERMINTMESSAGE"]._serialized_start = 51 + _globals["_TENDERMINTMESSAGE"]._serialized_end = 1248 + _globals["_TENDERMINTMESSAGE_ERRORCODE"]._serialized_start = 582 + _globals["_TENDERMINTMESSAGE_ERRORCODE"]._serialized_end = 724 + _globals["_TENDERMINTMESSAGE_ERRORCODE_ERRORCODEENUM"]._serialized_start = 688 + _globals["_TENDERMINTMESSAGE_ERRORCODE_ERRORCODEENUM"]._serialized_end = 724 + _globals["_TENDERMINTMESSAGE_GET_GENESIS_INFO_PERFORMATIVE"]._serialized_start = 726 + _globals["_TENDERMINTMESSAGE_GET_GENESIS_INFO_PERFORMATIVE"]._serialized_end = 794 + _globals[ + "_TENDERMINTMESSAGE_GET_RECOVERY_PARAMS_PERFORMATIVE" + ]._serialized_start = 796 + _globals[ + "_TENDERMINTMESSAGE_GET_RECOVERY_PARAMS_PERFORMATIVE" + ]._serialized_end = 867 + _globals["_TENDERMINTMESSAGE_GENESIS_INFO_PERFORMATIVE"]._serialized_start = 869 + _globals["_TENDERMINTMESSAGE_GENESIS_INFO_PERFORMATIVE"]._serialized_end = 910 + _globals["_TENDERMINTMESSAGE_RECOVERY_PARAMS_PERFORMATIVE"]._serialized_start = 912 + _globals["_TENDERMINTMESSAGE_RECOVERY_PARAMS_PERFORMATIVE"]._serialized_end = 958 + _globals["_TENDERMINTMESSAGE_ERROR_PERFORMATIVE"]._serialized_start = 961 + _globals["_TENDERMINTMESSAGE_ERROR_PERFORMATIVE"]._serialized_end = 1232 + _globals[ + "_TENDERMINTMESSAGE_ERROR_PERFORMATIVE_ERRORDATAENTRY" + ]._serialized_start = 1184 + _globals[ + "_TENDERMINTMESSAGE_ERROR_PERFORMATIVE_ERRORDATAENTRY" + ]._serialized_end = 1232 # @@protoc_insertion_point(module_scope) diff --git a/packages/valory/services/counter/service.yaml b/packages/valory/services/counter/service.yaml index fe62689444..208766d0bc 100644 --- a/packages/valory/services/counter/service.yaml +++ b/packages/valory/services/counter/service.yaml @@ -8,8 +8,9 @@ fingerprint: README.md: bafybeidoybzzjch4djhhafqm4e4jcrpaqmlthntcnonlsjtowwpykbc5xi fingerprint_ignore_patterns: [] number_of_agents: 1 -agent: valory/counter:0.1.0:bafybeigkxgd644pzmfigkcprpvv7fkchoj6syyfymvdpeiobpqawfdeq5i +agent: valory/counter:0.1.0:bafybeidueagnkdtcw4ptf6wjhqw53qsclmgqubw4eovxqip4eqdwtcp7sa deployment: {} +dependencies: {} --- public_id: valory/ledger:0.19.0 type: connection diff --git a/packages/valory/services/hello_world/README.md b/packages/valory/services/hello_world/README.md deleted file mode 100644 index 6f4e98add7..0000000000 --- a/packages/valory/services/hello_world/README.md +++ /dev/null @@ -1,3 +0,0 @@ -## Hello world - -This module contains the ABCI Hello World service for an AEA. It implements an ABCI application for a simple demonstration. diff --git a/packages/valory/services/hello_world/service.yaml b/packages/valory/services/hello_world/service.yaml deleted file mode 100644 index a6238f8c72..0000000000 --- a/packages/valory/services/hello_world/service.yaml +++ /dev/null @@ -1,79 +0,0 @@ -name: hello_world -author: valory -version: 0.1.0 -description: A simple demonstration of a simple ABCI application -aea_version: '>=1.0.0, <2.0.0' -license: Apache-2.0 -fingerprint: - README.md: bafybeiapubcoersqnsnh3acia5hd7otzt7kjxekr6gkbrlumv6tkajl6jm -fingerprint_ignore_patterns: [] -agent: valory/hello_world:0.1.0:bafybeidghah5yexnsdxwplnbyq3u3bgl2mmjur2eef4bxenf6ddb3zs2ca -number_of_agents: 4 -deployment: {} ---- -extra: - benchmark_persistence_params: - args: &id002 - log_dir: /benchmarks - params_args: - args: - setup: &id001 - all_participants: ${ALL_PARTICIPANTS:list:["0x0000000000000000000000000000000000000000"]} - safe_contract_address: '0x0000000000000000000000000000000000000000' - consensus_threshold: null -public_id: valory/hello_world_abci:0.1.0 -type: skill -0: - models: - params: - args: - service_registry_address: null - share_tm_config_on_startup: false - on_chain_service_id: null - setup: *id001 - hello_world_message: ${HELLO_WORLD_STRING_0:str:HELLO_WORLD! (from Agent 0)} - benchmark_tool: - args: *id002 -1: - models: - params: - args: - service_registry_address: null - share_tm_config_on_startup: false - on_chain_service_id: null - setup: *id001 - hello_world_message: ${HELLO_WORLD_STRING_1:str:HELLO_WORLD! (from Agent 1)} - benchmark_tool: - args: *id002 -2: - models: - params: - args: - service_registry_address: null - share_tm_config_on_startup: false - on_chain_service_id: null - setup: *id001 - hello_world_message: ${HELLO_WORLD_STRING_2:str:HELLO_WORLD! (from Agent 2)} - benchmark_tool: - args: *id002 -3: - models: - params: - args: - service_registry_address: null - share_tm_config_on_startup: false - on_chain_service_id: null - setup: *id001 - hello_world_message: ${HELLO_WORLD_STRING_3:str:HELLO_WORLD! (from Agent 3)} - benchmark_tool: - args: *id002 ---- -public_id: valory/ledger:0.19.0 -type: connection -config: - ledger_apis: - ethereum: - address: ${SERVICE_HELLO_WORLD_RPC:str:http://host.docker.internal:8545} - chain_id: 31337 - poa_chain: false - default_gas_price_strategy: eip1559 diff --git a/packages/valory/services/register_reset/service.yaml b/packages/valory/services/register_reset/service.yaml index e696167bfa..5325506cb3 100644 --- a/packages/valory/services/register_reset/service.yaml +++ b/packages/valory/services/register_reset/service.yaml @@ -1,7 +1,7 @@ name: register_reset author: valory version: 0.1.0 -agent: valory/register_reset:0.1.0:bafybeibs3dm6jixfv2m2k67mjduokbxdnod6esjo337tcoa7cudnspr76m +agent: valory/register_reset:0.1.0:bafybeigrvrcrpy4zmifvej33zhhoxrvsxfsi2ebsic6a3kdl4hy6angmve number_of_agents: 4 description: Test and debug tendermint reset mechanism. aea_version: '>=1.0.0, <2.0.0' @@ -10,6 +10,7 @@ fingerprint: README.md: bafybeiae4sog7e3hyjdujzp5qr2g3auobmqswqnaczh2zhlphuojnd2g6u fingerprint_ignore_patterns: [] deployment: {} +dependencies: {} --- public_id: valory/ledger:0.19.0 type: connection diff --git a/packages/valory/skills/abstract_abci/skill.yaml b/packages/valory/skills/abstract_abci/skill.yaml index 0b4934f3fa..5be97ba4e3 100644 --- a/packages/valory/skills/abstract_abci/skill.yaml +++ b/packages/valory/skills/abstract_abci/skill.yaml @@ -15,10 +15,10 @@ fingerprint: tests/test_handlers.py: bafybeieeuwtu35ddaevr2wgnk33l7kdhrx7ruoeb5jiltiyn65ufdcnopu fingerprint_ignore_patterns: [] connections: -- valory/abci:0.1.0:bafybeih2l6ssf5ebkvgbag3hx2pd22shytszqavveib2e2s6rv4va5khv4 +- valory/abci:0.1.0:bafybeih4lb2myvtypnfeji5jmgikmmazpgl3vyf5sy7oe66ji2zfjj6ily contracts: [] protocols: -- valory/abci:0.1.0:bafybeig3dj5jhsowlvg3t73kgobf6xn4nka7rkttakdb2gwsg5bp7rt7q4 +- valory/abci:0.1.0:bafybeihmzlmmb4pdo3zkhg6ehuyaa4lhw7bfpclln2o2z7v3o6fcep26iu skills: [] behaviours: {} handlers: diff --git a/packages/valory/skills/abstract_round_abci/__init__.py b/packages/valory/skills/abstract_round_abci/__init__.py index 48ce284dd8..aa07a64c8d 100644 --- a/packages/valory/skills/abstract_round_abci/__init__.py +++ b/packages/valory/skills/abstract_round_abci/__init__.py @@ -20,11 +20,6 @@ """This module contains an abstract round ABCI skill template for an AEA.""" # pragma: nocover from aea.configurations.base import PublicId # pragma: nocover -from hypothesis import settings # pragma: nocover PUBLIC_ID = PublicId.from_str("valory/abstract_round_abci:0.1.0") -CI = "CI" # pragma: nocover - - -settings.register_profile(CI, deadline=5000) # pragma: nocover diff --git a/packages/valory/skills/abstract_round_abci/abci_app_chain.py b/packages/valory/skills/abstract_round_abci/abci_app_chain.py index a221511631..2f1b413937 100644 --- a/packages/valory/skills/abstract_round_abci/abci_app_chain.py +++ b/packages/valory/skills/abstract_round_abci/abci_app_chain.py @@ -173,7 +173,7 @@ def get_paths( accumulated_post_conditions: Set[str] = current_app.db_pre_conditions.get( current_initial_state, set() ) - for (next_initial_state, next_app, next_final_state) in path[1:]: + for next_initial_state, next_app, next_final_state in path[1:]: if current_final_state is None: # No outwards transition, nothing to check. # we are at the end of a path where the last diff --git a/packages/valory/skills/abstract_round_abci/base.py b/packages/valory/skills/abstract_round_abci/base.py index d2b912a726..69317e9215 100644 --- a/packages/valory/skills/abstract_round_abci/base.py +++ b/packages/valory/skills/abstract_round_abci/base.py @@ -30,16 +30,20 @@ import textwrap import uuid from abc import ABC, ABCMeta, abstractmethod -from collections import Counter +from collections import Counter, deque from copy import copy, deepcopy -from dataclasses import asdict, astuple, dataclass, field +from dataclasses import asdict, astuple, dataclass, field, is_dataclass from enum import Enum from inspect import isclass +from math import ceil from typing import ( Any, + Callable, + Deque, Dict, FrozenSet, Generic, + Iterator, List, Mapping, Optional, @@ -54,12 +58,19 @@ from aea.crypto.ledger_apis import LedgerApis from aea.exceptions import enforce +from aea.skills.base import SkillContext from packages.valory.connections.abci.connection import MAX_READ_IN_BYTES from packages.valory.connections.ledger.connection import ( PUBLIC_ID as LEDGER_CONNECTION_PUBLIC_ID, ) -from packages.valory.protocols.abci.custom_types import Header +from packages.valory.protocols.abci.custom_types import ( + EvidenceType, + Evidences, + Header, + LastCommitInfo, + Validator, +) from packages.valory.skills.abstract_round_abci.utils import ( consensus_threshold, is_json_serializable, @@ -79,6 +90,9 @@ VALUE_NOT_PROVIDED = object() # tolerance in seconds for new blocks not having arrived yet BLOCKS_STALL_TOLERANCE = 60 +SERIOUS_OFFENCE_ENUM_MIN = 1000 +NUMBER_OF_BLOCKS_TRACKED = 10_000 +NUMBER_OF_ROUNDS_TRACKED = 50 EventType = TypeVar("EventType") @@ -475,6 +489,9 @@ class AbciAppDB: https://github.com/python/cpython/blob/3.10/Lib/copy.py#L182-L183 """ + DB_DATA_KEY = "db_data" + SLASHING_CONFIG_KEY = "slashing_config" + # database keys which values are always set for the next period by default default_cross_period_keys: FrozenSet[str] = frozenset( { @@ -510,6 +527,7 @@ def __init__( cross_period_persisted_keys or frozenset() ) self._cross_period_check() + self.slashing_config: str = "" def _cross_period_check(self) -> None: """Check the cross period keys against the setup data.""" @@ -681,7 +699,11 @@ def cleanup_current_histories(self, cleanup_history_depth_current: int) -> None: def serialize(self) -> str: """Serialize the data of the database to a string.""" - return json.dumps(self._data, sort_keys=True) + db = { + self.DB_DATA_KEY: self._data, + self.SLASHING_CONFIG_KEY: self.slashing_config, + } + return json.dumps(db, sort_keys=True) @staticmethod def _as_abci_data(data: Dict) -> Dict[int, Any]: @@ -696,22 +718,35 @@ def sync(self, serialized_data: str) -> None: """ try: loaded_data = json.loads(serialized_data) - loaded_data = self._as_abci_data(loaded_data) except json.JSONDecodeError as exc: raise ABCIAppInternalError( f"Could not decode data using {serialized_data}: {exc}" ) from exc + + input_report = f"\nThe following serialized data were given: {serialized_data}" + try: + db_data = loaded_data[self.DB_DATA_KEY] + slashing_config = loaded_data[self.SLASHING_CONFIG_KEY] + except KeyError as exc: + raise ABCIAppInternalError( + "Mandatory keys `db_data`, `slashing_config` are missing from the deserialized data: " + f"{loaded_data}{input_report}" + ) from exc + + try: + db_data = self._as_abci_data(db_data) except AttributeError as exc: raise ABCIAppInternalError( - f"Could not decode db data with an invalid format: {serialized_data}" + f"Could not decode db data with an invalid format: {db_data}{input_report}" ) from exc except ValueError as exc: raise ABCIAppInternalError( - f"An invalid index was found while trying to sync the db using data: {serialized_data}" + f"An invalid index was found while trying to sync the db using data: {db_data}{input_report}" ) from exc - self._check_data(dict(tuple(loaded_data.values())[0])) - self._data = loaded_data + self._check_data(dict(tuple(db_data.values())[0])) + self._data = db_data + self.slashing_config = slashing_config def hash(self) -> bytes: """Create a hash of the data.""" @@ -851,6 +886,16 @@ def nb_participants(self) -> int: participants = cast(List, self.db.get("participants", [])) return len(participants) + @property + def slashing_config(self) -> str: + """Get the slashing configuration.""" + return self.db.slashing_config + + @slashing_config.setter + def slashing_config(self, config: str) -> None: + """Set the slashing configuration.""" + self.db.slashing_config = config + def update( self, synchronized_data_class: Optional[Type] = None, @@ -997,12 +1042,14 @@ class AbstractRound(Generic[EventType], ABC, metaclass=_MetaAbstractRound): def __init__( self, synchronized_data: BaseSynchronizedData, + context: SkillContext, previous_round_payload_class: Optional[Type[BaseTxPayload]] = None, ) -> None: """Initialize the round.""" self._synchronized_data = synchronized_data self.block_confirmations = 0 self._previous_round_payload_class = previous_round_payload_class + self.context = context @classmethod def auto_round_id(cls) -> str: @@ -1901,6 +1948,8 @@ def pop_timeout(self) -> Tuple[datetime.datetime, Any]: class _MetaAbciApp(ABCMeta): """A metaclass that validates AbciApp's attributes.""" + bg_round_added: bool = False + def __new__(mcs, name: str, bases: Tuple, namespace: Dict, **kwargs: Any) -> Type: # type: ignore """Initialize the class.""" new_cls = super().__new__(mcs, name, bases, namespace, **kwargs) @@ -1912,7 +1961,12 @@ def __new__(mcs, name: str, bases: Tuple, namespace: Dict, **kwargs: Any) -> Typ # the check only applies to AbciApp subclasses return new_cls + if not mcs.bg_round_added: + mcs._add_pending_offences_bg_round(new_cls) + mcs.bg_round_added = True + mcs._check_consistency(cast(Type[AbciApp], new_cls)) + return new_cls @classmethod @@ -2091,6 +2145,159 @@ def _check_consistency_outgoing_transitions_from_non_final_states( f"non-timeout transition", ) + @classmethod + def _add_pending_offences_bg_round(cls, abci_app_cls: Type["AbciApp"]) -> None: + """Add the pending offences synchronization background round.""" + config: BackgroundAppConfig = BackgroundAppConfig(PendingOffencesRound) + abci_app_cls.add_background_app(config) + + +class BackgroundAppType(Enum): + """ + The type of a background app. + + Please note that the values correspond to the priority in which the background apps should be processed + when updating rounds. + """ + + TERMINATING = 0 + EVER_RUNNING = 1 + NORMAL = 2 + INCORRECT = 3 + + @staticmethod + def correct_types() -> Set[str]: + """Return the correct types only.""" + return set(BackgroundAppType.__members__) - {BackgroundAppType.INCORRECT.name} + + +@dataclass(frozen=True) +class BackgroundAppConfig(Generic[EventType]): + """ + Necessary configuration for a background app. + + For a deeper understanding of the various types of background apps and how the config influences + the generated background app's type, please refer to the `BackgroundApp` class. + The `specify_type` method provides further insight on the subject matter. + """ + + # the class of the background round + round_cls: AppState + # the abci app of the background round + # the abci app must specify a valid transition function if the round is not of an ever-running type + abci_app: Optional[Type["AbciApp"]] = None + # the start event of the background round + # if no event or transition function is specified, then the round is running in the background forever + start_event: Optional[EventType] = None + # the end event of the background round + # if not specified, then the round is terminating the abci app + end_event: Optional[EventType] = None + + +class BackgroundApp(Generic[EventType]): + """A background app.""" + + def __init__( + self, + config: BackgroundAppConfig, + ) -> None: + """Initialize the BackgroundApp.""" + given_args = locals() + + self.config = config + self.round_cls: AppState = config.round_cls + self.transition_function: Optional[AbciAppTransitionFunction] = ( + config.abci_app.transition_function if config.abci_app is not None else None + ) + self.start_event: Optional[EventType] = config.start_event + self.end_event: Optional[EventType] = config.end_event + + self.type = self.specify_type() + if self.type == BackgroundAppType.INCORRECT: # pragma: nocover + raise ValueError( + f"Background app has not been initialized correctly with {given_args}. " + f"Cannot match with any of the possible background apps' types: {BackgroundAppType.correct_types()}" + ) + _logger.debug( + f"Created background app of type '{self.type}' using {given_args}." + ) + self._background_round: Optional[AbstractRound] = None + + def __eq__(self, other: Any) -> bool: # pragma: no cover + """Custom equality comparing operator.""" + if not isinstance(other, BackgroundApp): + return False + + return self.config == other.config + + def __hash__(self) -> int: + """Custom hashing operator""" + return hash(self.config) + + def specify_type(self) -> BackgroundAppType: + """Specify the type of the background app.""" + if ( + self.start_event is None + and self.end_event is None + and self.transition_function is None + ): + self.transition_function = {} + return BackgroundAppType.EVER_RUNNING + if ( + self.start_event is not None + and self.end_event is None + and self.transition_function is not None + ): + return BackgroundAppType.TERMINATING + if ( + self.start_event is not None + and self.end_event is not None + and self.transition_function is not None + ): + return BackgroundAppType.NORMAL + return BackgroundAppType.INCORRECT # pragma: nocover + + def setup( + self, initial_synchronized_data: BaseSynchronizedData, context: SkillContext + ) -> None: + """Set up the background round.""" + round_cls = cast(Type[AbstractRound], self.round_cls) + self._background_round = round_cls( + initial_synchronized_data, + context, + ) + + @property + def background_round(self) -> AbstractRound: + """Get the background round.""" + if self._background_round is None: # pragma: nocover + raise ValueError(f"Background round with class `{self.round_cls}` not set!") + return self._background_round + + def process_transaction(self, transaction: Transaction, dry: bool = False) -> bool: + """Process a transaction.""" + + payload_class = type(transaction.payload) + bg_payload_class = cast(AppState, self.round_cls).payload_class + if payload_class is bg_payload_class: + processor = ( + self.background_round.check_transaction + if dry + else self.background_round.process_transaction + ) + processor(transaction) + return True + return False + + +@dataclass +class TransitionBackup: + """Holds transition related information as a backup in case we want to transition back from a background app.""" + + round: Optional[AbstractRound] = None + round_cls: Optional[AppState] = None + transition_function: Optional[AbciAppTransitionFunction] = None + class AbciApp( Generic[EventType], ABC, metaclass=_MetaAbciApp @@ -2107,9 +2314,7 @@ class AbciApp( final_states: Set[AppState] = set() event_to_timeout: EventToTimeout = {} cross_period_persisted_keys: FrozenSet[str] = frozenset() - background_round_cls: Optional[AppState] = None - termination_transition_function: Optional[AbciAppTransitionFunction] = None - termination_event: Optional[EventType] = None + background_apps: Set[BackgroundApp] = set() default_db_preconditions: Set[str] = BaseSynchronizedData.default_db_keys db_pre_conditions: Dict[AppState, Set[str]] = {} db_post_conditions: Dict[AppState, Set[str]] = {} @@ -2119,6 +2324,7 @@ def __init__( self, synchronized_data: BaseSynchronizedData, logger: logging.Logger, + context: SkillContext, ): """Initialize the AbciApp.""" @@ -2127,10 +2333,9 @@ def __init__( self._initial_synchronized_data = synchronized_data self.logger = logger - + self.context = context self._current_round_cls: Optional[AppState] = None self._current_round: Optional[AbstractRound] = None - self._background_round: Optional[AbstractRound] = None self._last_round: Optional[AbstractRound] = None self._previous_rounds: List[AbstractRound] = [] self._current_round_height: int = 0 @@ -2138,11 +2343,8 @@ def __init__( self._last_timestamp: Optional[datetime.datetime] = None self._current_timeout_entries: List[int] = [] self._timeouts = Timeouts[EventType]() - self._is_termination_set = ( - self.background_round_cls is not None - and self.termination_transition_function is not None - and self.termination_event is not None - ) + self._transition_backup = TransitionBackup() + self._switched = False @classmethod def is_abstract(cls) -> bool: @@ -2150,19 +2352,29 @@ def is_abstract(cls) -> bool: return cls._is_abstract @classmethod - def add_termination( + def add_background_app( cls, - background_round_cls: AppState, - termination_event: EventType, - termination_abci_app: Type["AbciApp"], + config: BackgroundAppConfig, ) -> Type["AbciApp"]: - """Sets the termination related class variables.""" - cls.background_round_cls = background_round_cls - cls.termination_transition_function = termination_abci_app.transition_function - cls.termination_event = termination_event - new_cross_period_persisted_keys = copy(cls.cross_period_persisted_keys) - cls.cross_period_persisted_keys = new_cross_period_persisted_keys.union( - termination_abci_app.cross_period_persisted_keys + """ + Sets the background related class variables. + + For a deeper understanding of the various types of background apps and how the inputs of this method influence + the generated background app's type, please refer to the `BackgroundApp` class. + The `specify_type` method provides further insight on the subject matter. + + :param config: the background app's configuration. + :return: the `AbciApp` with the new background app contained in the `background_apps` set. + """ + background_app: BackgroundApp = BackgroundApp(config) + cls.background_apps.add(background_app) + cross_period_keys = ( + config.abci_app.cross_period_persisted_keys + if config.abci_app is not None + else frozenset() + ) + cls.cross_period_persisted_keys = cls.cross_period_persisted_keys.union( + cross_period_keys ) return cls @@ -2209,18 +2421,38 @@ def _get_rounds_from_transition_function( @classmethod def get_all_round_classes( - cls, include_termination_rounds: bool = False + cls, + bg_round_cls: Set[Type[AbstractRound]], + include_background_rounds: bool = False, ) -> Set[AppState]: """Get all round classes.""" - result: Set[AppState] = cls._get_rounds_from_transition_function( - cls.transition_function - ) - if include_termination_rounds: - termination_rounds = cls._get_rounds_from_transition_function( - cls.termination_transition_function, - ) - result.update(termination_rounds) - return result + full_fn = deepcopy(cls.transition_function) + + if include_background_rounds: + for app in cls.background_apps: + if ( + app.type != BackgroundAppType.EVER_RUNNING + and app.round_cls in bg_round_cls + ): + transition_fn = cast( + AbciAppTransitionFunction, app.transition_function + ) + full_fn.update(transition_fn) + + return cls._get_rounds_from_transition_function(full_fn) + + @property + def bg_apps_prioritized(self) -> Tuple[List[BackgroundApp], ...]: + """Get the background apps grouped and prioritized by their types.""" + n_correct_types = len(BackgroundAppType.correct_types()) + grouped_prioritized: Tuple[List, ...] = ([],) * n_correct_types + for app in self.background_apps: + # reminder: the values correspond to the priority of the background apps + for priority in range(n_correct_types): + if app.type == BackgroundAppType(priority): + grouped_prioritized[priority].append(app) + + return grouped_prioritized @property def last_timestamp(self) -> datetime.datetime: @@ -2229,14 +2461,15 @@ def last_timestamp(self) -> datetime.datetime: raise ABCIAppInternalError("last timestamp is None") return self._last_timestamp + def _setup_background(self) -> None: + """Set up the background rounds.""" + for app in self.background_apps: + app.setup(self._initial_synchronized_data, self.context) + def setup(self) -> None: """Set up the behaviour.""" self.schedule_round(self.initial_round_cls) - if self.is_termination_set: - self.background_round_cls = cast(AppState, self.background_round_cls) - self._background_round = self.background_round_cls( - self._initial_synchronized_data, - ) + self._setup_background() def _log_start(self) -> None: """Log the entering in the round.""" @@ -2296,12 +2529,14 @@ def schedule_round(self, round_cls: AppState) -> None: self._current_round_cls = round_cls self._current_round = round_cls( self.synchronized_data, + self.context, ( self._last_round.payload_class if self._last_round is not None and self._last_round.payload_class != self._current_round_cls.payload_class - # when transitioning to a round with the same payload type we set None as otherwise it will allow no tx to be sumitted + # when transitioning to a round with the same payload type we set None + # as otherwise it will allow no tx to be submitted else None ), ) @@ -2315,18 +2550,6 @@ def current_round(self) -> AbstractRound: raise ValueError("current_round not set!") return self._current_round - @property - def background_round(self) -> AbstractRound: - """Get the background round.""" - if self._background_round is None: - raise ValueError("background_round not set!") - return self._background_round - - @property - def is_termination_set(self) -> bool: - """Get whether termination is set.""" - return self._is_termination_set - @property def current_round_id(self) -> Optional[str]: """Get the current round id.""" @@ -2364,44 +2587,122 @@ def cleanup_timeouts(self) -> None: self._last_timestamp = None def check_transaction(self, transaction: Transaction) -> None: + """Check a transaction.""" + + self.process_transaction(transaction, dry=True) + + def process_transaction(self, transaction: Transaction, dry: bool = False) -> None: """ - Check a transaction. + Process a transaction. - The background round runs concurrently with other (normal) rounds. - First we check if the transaction is meant for the background round, - if not we forward to the current round object. + The background rounds run concurrently with other (normal) rounds. + First we check if the transaction is meant for a background round, + if not we forward it to the current round object. :param transaction: the transaction. + :param dry: whether the transaction should only be checked and not processed. """ - payload_type = type(transaction.payload) - if ( - self.is_termination_set - and payload_type is cast(AppState, self.background_round_cls).payload_class - ): - self.background_round.check_transaction(transaction) - return - self.current_round.check_transaction(transaction) + for app in self.background_apps: + processed = app.process_transaction(transaction, dry) + if processed: + return - def process_transaction(self, transaction: Transaction) -> None: + processor = ( + self.current_round.check_transaction + if dry + else self.current_round.process_transaction + ) + processor(transaction) + + def _resolve_bg_transition( + self, app: BackgroundApp, event: EventType + ) -> Tuple[bool, Optional[AppState]]: """ - Process a transaction. + Resolve a background app's transition. - The background round runs concurrently with other (normal) rounds. - First we check if the transaction is meant for the background round, - if not we forward to the current round object. + First check whether the event is a special start event. + If that's the case, proceed with the corresponding background app's transition function, + regardless of what the current round is. - :param transaction: the transaction. + :param app: the background app instance. + :param event: the event for the transition. + :return: the new app state. """ - payload_type = type(transaction.payload) if ( - self.is_termination_set - and payload_type is cast(AppState, self.background_round_cls).payload_class + app.type in (BackgroundAppType.NORMAL, BackgroundAppType.TERMINATING) + and event == app.start_event ): - self.background_round.process_transaction(transaction) + app.transition_function = cast( + AbciAppTransitionFunction, app.transition_function + ) + app.round_cls = cast(AppState, app.round_cls) + next_round_cls = app.transition_function[app.round_cls].get(event, None) + if next_round_cls is None: # pragma: nocover + return True, None + + # we backup the current round so we can return back to normal, in case the end event is received later + self._transition_backup.round = self._current_round + self._transition_backup.round_cls = self._current_round_cls + # we switch the current transition function, with the background app's transition function + self._transition_backup.transition_function = deepcopy( + self.transition_function + ) + self.transition_function = app.transition_function + self.logger.info( + f"The {event} event was produced, transitioning to " + f"`{next_round_cls.auto_round_id()}`." + ) + return True, next_round_cls + + return False, None + + def _adjust_transition_fn(self, event: EventType) -> None: + """ + Adjust the transition function if necessary. + + Check whether the event is a special end event. + If that's the case, reset the transition function back to normal. + This method is meant to be called after resolving the next round transition, given an event. + + :param event: the emitted event. + """ + if self._transition_backup.transition_function is None: return - self.current_round.process_transaction(transaction) + + for app in self.background_apps: + if app.type == BackgroundAppType.NORMAL and event == app.end_event: + self._current_round = self._transition_backup.round + self._transition_backup.round = None + self._current_round_cls = self._transition_backup.round_cls + self._transition_backup.round_cls = None + backup_fn = cast( + AbciAppTransitionFunction, + self._transition_backup.transition_function, + ) + self.transition_function = deepcopy(backup_fn) + self._transition_backup.transition_function = None + self._switched = True + self.logger.info( + f"The {app.end_event} event was produced. Switching back to the normal FSM." + ) + + def _resolve_transition(self, event: EventType) -> Optional[Type[AbstractRound]]: + """Resolve the transitioning based on the given event.""" + for app in self.background_apps: + matched, next_round_cls = self._resolve_bg_transition(app, event) + if matched: + return next_round_cls + + self._adjust_transition_fn(event) + + current_round_cls = cast(AppState, self._current_round_cls) + next_round_cls = self.transition_function[current_round_cls].get(event, None) + if next_round_cls is None: + return None + + return next_round_cls def process_event( self, event: EventType, result: Optional[BaseSynchronizedData] = None @@ -2413,45 +2714,24 @@ def process_event( ) return - # we first check whether the event is the special termination event. - # if that's the case, we proceed with the termination transition function, - # regardless of what the current round is - if self.is_termination_set and event == self.termination_event: - self.termination_transition_function = cast( - AbciAppTransitionFunction, self.termination_transition_function - ) - self.background_round_cls = cast(AppState, self.background_round_cls) - next_round_cls = self.termination_transition_function[ - self.background_round_cls - ].get(event, None) - - # we switch the current transition function, with the termination - # transition function. Note that we don't need to return to the - # normal transition function (self.transition_function) because - # the termination transition function is sufficient for going - # through the necessary rounds - self.transition_function = self.termination_transition_function - self.logger.info( - f"The termination event was produced, transitioning to `{cast(AppState, next_round_cls).auto_round_id()}`." - ) - else: - next_round_cls = self.transition_function[self._current_round_cls].get( - event, None - ) + next_round_cls = self._resolve_transition(event) self._extend_previous_rounds_with_current_round() - if result is not None: - self._round_results.append(result) - else: - # we duplicate the state since the round was preemptively ended - self._round_results.append(self.current_round.synchronized_data) + # if there is no result, we duplicate the state since the round was preemptively ended + result = self.current_round.synchronized_data if result is None else result + self._round_results.append(result) self._log_end(event) if next_round_cls is not None: self.schedule_round(next_round_cls) - else: - self.logger.warning("AbciApp has reached a dead end.") - self._current_round_cls = None - self._current_round = None + return + + if self._switched: + self._switched = False + return + + self.logger.warning("AbciApp has reached a dead end.") + self._current_round_cls = None + self._current_round = None def update_time(self, timestamp: datetime.datetime) -> None: """ @@ -2531,6 +2811,288 @@ def cleanup_current_histories(self, cleanup_history_depth_current: int) -> None: ) +class OffenseType(Enum): + """ + The types of offenses. + + The values of the enum represent the seriousness of the offence. + Offense types with values >1000 are considered serious. + See also `is_light_offence` and `is_serious_offence` functions. + """ + + NO_OFFENCE = -1 + VALIDATOR_DOWNTIME = 0 + INVALID_PAYLOAD = 1 + BLACKLISTED = 2 + SUSPECTED = 3 + UNKNOWN = SERIOUS_OFFENCE_ENUM_MIN + DOUBLE_SIGNING = SERIOUS_OFFENCE_ENUM_MIN + 1 + LIGHT_CLIENT_ATTACK = SERIOUS_OFFENCE_ENUM_MIN + 2 + + +def is_light_offence(offence_type: OffenseType) -> bool: + """Check if an offence type is light.""" + return 0 <= offence_type.value < SERIOUS_OFFENCE_ENUM_MIN + + +def is_serious_offence(offence_type: OffenseType) -> bool: + """Check if an offence type is serious.""" + return offence_type.value >= SERIOUS_OFFENCE_ENUM_MIN + + +def light_offences() -> Iterator[OffenseType]: + """Get the light offences.""" + return filter(is_light_offence, OffenseType) + + +def serious_offences() -> Iterator[OffenseType]: + """Get the serious offences.""" + return filter(is_serious_offence, OffenseType) + + +class AvailabilityWindow: + """ + A cyclic array with a maximum length that holds boolean values. + + When an element is added to the array and the maximum length has been reached, + the oldest element is removed. Two attributes `num_positive` and `num_negative` + reflect the number of positive and negative elements in the AvailabilityWindow, + they are updated every time a new element is added. + """ + + def __init__(self, max_length: int) -> None: + """ + Initializes the `AvailabilityWindow` instance. + + :param max_length: the maximum length of the cyclic array. + """ + if max_length < 1: + raise ValueError( + f"An `AvailabilityWindow` with a `max_length` {max_length} < 1 is not valid." + ) + + self._max_length = max_length + self._window: Deque[bool] = deque(maxlen=max_length) + self._num_positive = 0 + self._num_negative = 0 + + def __eq__(self, other: Any) -> bool: + """Compare `AvailabilityWindow` objects.""" + if isinstance(other, AvailabilityWindow): + return self.to_dict() == other.to_dict() + return False + + def has_bad_availability_rate(self, threshold: float = 0.95) -> bool: + """Whether the agent on which the window belongs to has a bad availability rate or not.""" + return self._num_positive >= ceil(self._max_length * threshold) + + def _update_counters(self, positive: bool, removal: bool = False) -> None: + """Updates the `num_positive` and `num_negative` counters.""" + update_amount = -1 if removal else 1 + + if positive: + if self._num_positive == 0 and update_amount == -1: # pragma: no cover + return + self._num_positive += update_amount + else: + if self._num_negative == 0 and update_amount == -1: # pragma: no cover + return + self._num_negative += update_amount + + def add(self, value: bool) -> None: + """ + Adds a new boolean value to the cyclic array. + + If the maximum length has been reached, the oldest element is removed. + + :param value: The boolean value to add to the cyclic array. + """ + if len(self._window) == self._max_length and self._max_length > 0: + # we have filled the window, we need to pop the oldest element + # and update the score accordingly + oldest_value = self._window.popleft() + self._update_counters(oldest_value, removal=True) + + self._window.append(value) + self._update_counters(value) + + def to_dict(self) -> Dict[str, int]: + """Returns a dictionary representation of the `AvailabilityWindow` instance.""" + return { + "max_length": self._max_length, + # Please note that the value cannot be represented if the max length of the availability window is > 14_285 + "array": int("".join(str(int(flag)) for flag in self._window), base=2) + if len(self._window) + else 0, + "num_positive": self._num_positive, + "num_negative": self._num_negative, + } + + @staticmethod + def _validate_key( + data: Dict[str, int], key: str, validator: Callable[[int], bool] + ) -> None: + """Validate the given key in the data.""" + value = data.get(key, None) + if value is None: + raise ValueError(f"Missing required key: {key}.") + + if not isinstance(value, int): + raise ValueError(f"{key} must be of type int.") + + if not validator(value): + raise ValueError(f"{key} has invalid value {value}.") + + @staticmethod + def _validate(data: Dict[str, int]) -> None: + """Check if the input can be properly mapped to the class attributes.""" + if not isinstance(data, dict): + raise TypeError(f"Expected dict, got {type(data)}") + + attribute_to_validator = { + "max_length": lambda x: x > 0, + "array": lambda x: 0 <= x < 2 ** data["max_length"], + "num_positive": lambda x: x >= 0, + "num_negative": lambda x: x >= 0, + } + + errors = [] + for attribute, validator in attribute_to_validator.items(): + try: + AvailabilityWindow._validate_key(data, attribute, validator) + except ValueError as e: + errors.append(str(e)) + + if errors: + raise ValueError("Invalid input:\n" + "\n".join(errors)) + + @classmethod + def from_dict(cls, data: Dict[str, int]) -> "AvailabilityWindow": + """Initializes an `AvailabilityWindow` instance from a dictionary.""" + cls._validate(data) + + # convert the serialized array to a binary string + binary_number = bin(data["array"])[2:] + # convert each character in the binary string to a flag + flags = (bool(int(digit)) for digit in binary_number) + + instance = cls(max_length=data["max_length"]) + instance._window.extend(flags) + instance._num_positive = data["num_positive"] + instance._num_negative = data["num_negative"] + return instance + + +@dataclass +class OffenceStatus: + """A class that holds information about offence status for an agent.""" + + validator_downtime: AvailabilityWindow = field( + default_factory=lambda: AvailabilityWindow(NUMBER_OF_BLOCKS_TRACKED) + ) + invalid_payload: AvailabilityWindow = field( + default_factory=lambda: AvailabilityWindow(NUMBER_OF_ROUNDS_TRACKED) + ) + blacklisted: AvailabilityWindow = field( + default_factory=lambda: AvailabilityWindow(NUMBER_OF_ROUNDS_TRACKED) + ) + suspected: AvailabilityWindow = field( + default_factory=lambda: AvailabilityWindow(NUMBER_OF_ROUNDS_TRACKED) + ) + num_unknown_offenses: int = 0 + num_double_signed: int = 0 + num_light_client_attack: int = 0 + + def slash_amount(self, light_unit_amount: int, serious_unit_amount: int) -> int: + """Get the slash amount of the current status.""" + offence_types = [] + + if self.validator_downtime.has_bad_availability_rate(): + offence_types.append(OffenseType.VALIDATOR_DOWNTIME) + if self.invalid_payload.has_bad_availability_rate(): + offence_types.append(OffenseType.INVALID_PAYLOAD) + if self.blacklisted.has_bad_availability_rate(): + offence_types.append(OffenseType.BLACKLISTED) + if self.suspected.has_bad_availability_rate(): + offence_types.append(OffenseType.SUSPECTED) + offence_types.extend([OffenseType.UNKNOWN] * self.num_unknown_offenses) + offence_types.extend([OffenseType.UNKNOWN] * self.num_double_signed) + offence_types.extend([OffenseType.UNKNOWN] * self.num_light_client_attack) + + light_multiplier = 0 + serious_multiplier = 0 + for offence_type in offence_types: + light_multiplier += bool(is_light_offence(offence_type)) + serious_multiplier += bool(is_serious_offence(offence_type)) + + return ( + light_multiplier * light_unit_amount + + serious_multiplier * serious_unit_amount + ) + + +class OffenseStatusEncoder(json.JSONEncoder): + """A custom JSON encoder for the offence status dictionary.""" + + def default(self, o: Any) -> Any: + """The default JSON encoder.""" + if is_dataclass(o): + return asdict(o) + if isinstance(o, AvailabilityWindow): + return o.to_dict() + return super().default(o) + + +class OffenseStatusDecoder(json.JSONDecoder): + """A custom JSON decoder for the offence status dictionary.""" + + def __init__(self, *args: Any, **kwargs: Any) -> None: + """Initialize the custom JSON decoder.""" + super().__init__(object_hook=self.hook, *args, **kwargs) + + @staticmethod + def hook( + data: Dict[str, Any] + ) -> Union[AvailabilityWindow, OffenceStatus, Dict[str, OffenceStatus]]: + """Perform the custom decoding.""" + # if this is an `AvailabilityWindow` + window_attributes = sorted(AvailabilityWindow(1).to_dict().keys()) + if window_attributes == sorted(data.keys()): + return AvailabilityWindow.from_dict(data) + + # if this is an `OffenceStatus` + status_attributes = ( + OffenceStatus.__annotations__.keys() # pylint: disable=no-member + ) + if sorted(status_attributes) == sorted(data.keys()): + return OffenceStatus(**data) + + return data + + +@dataclass(frozen=True, eq=True) +class PendingOffense: + """A dataclass to represent offences that need to be addressed.""" + + accused_agent_address: str + round_count: int + offense_type: OffenseType + last_transition_timestamp: float + time_to_live: float + + def __post_init__(self) -> None: + """Post initialization for offence type conversion in case it is given as an `int`.""" + if isinstance(self.offense_type, int): + super().__setattr__("offense_type", OffenseType(self.offense_type)) + + +class SlashingNotConfiguredError(Exception): + """Custom exception raised when slashing configuration is requested but is not available.""" + + +DEFAULT_PENDING_OFFENCE_TTL = 2 * 60 * 60 # 1 hour + + class RoundSequence: # pylint: disable=too-many-instance-attributes """ This class represents a sequence of rounds @@ -2563,11 +3125,11 @@ class _BlockConstructionState(Enum): WAITING_FOR_DELIVER_TX = "waiting_for_deliver_tx" WAITING_FOR_COMMIT = "waiting_for_commit" - def __init__(self, abci_app_cls: Type[AbciApp]): + def __init__(self, context: SkillContext, abci_app_cls: Type[AbciApp]): """Initialize the round.""" self._blockchain = Blockchain() self._syncing_up = True - + self._context = context self._block_construction_phase = ( RoundSequence._BlockConstructionState.WAITING_FOR_BEGIN_BLOCK ) @@ -2581,7 +3143,101 @@ def __init__(self, abci_app_cls: Type[AbciApp]): self._last_round_transition_tm_height: Optional[int] = None self._tm_height: Optional[int] = None self._block_stall_deadline: Optional[datetime.datetime] = None - self._termination_called: bool = False + self._terminating_round_called: bool = False + # a mapping of the validators' addresses to their agent addresses + # we create a mapping to avoid calculating the agent address from the validator address every time we need it + # since this is an operation that will be performed every time we want to create an offence + self._validator_to_agent: Dict[str, str] = {} + # a mapping of the agents' addresses to their offence status + self._offence_status: Dict[str, OffenceStatus] = {} + self._slashing_enabled = False + self.pending_offences: Set[PendingOffense] = set() + + def enable_slashing(self) -> None: + """Enable slashing.""" + self._slashing_enabled = True + + @property + def validator_to_agent(self) -> Dict[str, str]: + """Get the mapping of the validators' addresses to their agent addresses.""" + if self._validator_to_agent: + return self._validator_to_agent + raise SlashingNotConfiguredError( + "The mapping of the validators' addresses to their agent addresses has not been set." + ) + + @validator_to_agent.setter + def validator_to_agent(self, validator_to_agent: Dict[str, str]) -> None: + """Set the mapping of the validators' addresses to their agent addresses.""" + if self._validator_to_agent: + raise ValueError( + "The mapping of the validators' addresses to their agent addresses can only be set once. " + f"Attempted to set with {validator_to_agent} but it has content already: {self._validator_to_agent}." + ) + self._validator_to_agent = validator_to_agent + + @property + def offence_status(self) -> Dict[str, OffenceStatus]: + """Get the mapping of the agents' addresses to their offence status.""" + if self._offence_status: + return self._offence_status + raise SlashingNotConfiguredError( # pragma: nocover + "The mapping of the agents' addresses to their offence status has not been set." + ) + + @offence_status.setter + def offence_status(self, offence_status: Dict[str, OffenceStatus]) -> None: + """Set the mapping of the agents' addresses to their offence status.""" + self.abci_app.logger.debug(f"Setting offence status to: {offence_status}") + self._offence_status = offence_status + self.store_offence_status() + + def add_pending_offence(self, pending_offence: PendingOffense) -> None: + """ + Add a pending offence to the set of pending offences. + + Pending offences are offences that have been detected, but not yet agreed upon by the consensus. + A pending offence is removed from the set of pending offences and added to the OffenceStatus of a validator + when the majority of the agents agree on it. + + :param pending_offence: the pending offence to add + :return: None + """ + self.pending_offences.add(pending_offence) + + def sync_db_and_slashing(self, serialized_db_state: str) -> None: + """Sync the database and the slashing configuration.""" + self.abci_app.synchronized_data.db.sync(serialized_db_state) + offence_status = self.latest_synchronized_data.slashing_config + if offence_status: + # deserialize the offence status and load it to memory + self.offence_status = json.loads( + offence_status, + cls=OffenseStatusDecoder, + ) + + def serialized_offence_status(self) -> str: + """Serialize the offence status.""" + return json.dumps(self.offence_status, cls=OffenseStatusEncoder, sort_keys=True) + + def store_offence_status(self) -> None: + """Store the serialized offence status.""" + encoded_status = self.serialized_offence_status() + self.latest_synchronized_data.slashing_config = encoded_status + self.abci_app.logger.debug(f"Updated db with: {encoded_status}") + self.abci_app.logger.debug(f"App hash now is: {self.root_hash.hex()}") + + def get_agent_address(self, validator: Validator) -> str: + """Get corresponding agent address from a `Validator` instance.""" + validator_address = validator.address.hex().upper() + + try: + return self.validator_to_agent[validator_address] + except KeyError as exc: + raise ValueError( + f"Requested agent address for an unknown validator address {validator_address}. " + f"Available validators are: {self.validator_to_agent.keys()}" + ) from exc def setup(self, *args: Any, **kwargs: Any) -> None: """ @@ -2590,6 +3246,7 @@ def setup(self, *args: Any, **kwargs: Any) -> None: :param args: the arguments to pass to the round constructor. :param kwargs: the keyword-arguments to pass to the round constructor. """ + kwargs["context"] = self._context self._abci_app = self._abci_app_cls(*args, **kwargs) self._abci_app.setup() @@ -2656,11 +3313,6 @@ def current_round(self) -> AbstractRound: """Get current round.""" return self.abci_app.current_round - @property - def background_round(self) -> AbstractRound: - """Get the background round.""" - return self.abci_app.background_round - @property def current_round_id(self) -> Optional[str]: """Get the current round id.""" @@ -2770,12 +3422,84 @@ def block_stall_deadline_expired(self) -> bool: return False return datetime.datetime.now() > self._block_stall_deadline + def set_block_stall_deadline(self) -> None: + """Use the local time of the agent and a predefined tolerance, to specify the expiration of the deadline.""" + self._block_stall_deadline = datetime.datetime.now() + datetime.timedelta( + seconds=BLOCKS_STALL_TOLERANCE + ) + def init_chain(self, initial_height: int) -> None: """Init chain.""" # reduce `initial_height` by 1 to get block count offset as per Tendermint protocol self._blockchain = Blockchain(initial_height - 1) - def begin_block(self, header: Header) -> None: + def _track_tm_offences( + self, evidences: Evidences, last_commit_info: LastCommitInfo + ) -> None: + """Track offences provided by Tendermint, if there are any.""" + for vote_info in last_commit_info.votes: + agent_address = self.get_agent_address(vote_info.validator) + was_down = not vote_info.signed_last_block + self.offence_status[agent_address].validator_downtime.add(was_down) + + for byzantine_validator in evidences.byzantine_validators: + agent_address = self.get_agent_address(byzantine_validator.validator) + evidence_type = byzantine_validator.evidence_type + self.offence_status[agent_address].num_unknown_offenses += bool( + evidence_type == EvidenceType.UNKNOWN + ) + self.offence_status[agent_address].num_double_signed += bool( + evidence_type == EvidenceType.DUPLICATE_VOTE + ) + self.offence_status[agent_address].num_light_client_attack += bool( + evidence_type == EvidenceType.LIGHT_CLIENT_ATTACK + ) + + def _track_app_offences(self) -> None: + """Track offences provided by the app level, if there are any.""" + synced_data = self.abci_app.synchronized_data + for agent in self.offence_status.keys(): + blacklisted = agent in synced_data.blacklisted_keepers + suspected = agent in cast(tuple, synced_data.db.get("suspects", tuple())) + agent_status = self.offence_status[agent] + agent_status.blacklisted.add(blacklisted) + agent_status.suspected.add(suspected) + + def _handle_slashing_not_configured(self, exc: SlashingNotConfiguredError) -> None: + """Handle a `SlashingNotConfiguredError`.""" + # In the current slashing implementation, we do not track offences before setting the slashing + # configuration, i.e., before successfully sharing the tm configuration via ACN on registration. + # That is because we cannot slash an agent if we do not map their validator address to their agent address. + # Checking the number of participants will allow us to identify whether the registration round has finished, + # and therefore expect that the slashing configuration has been set if ACN registration is enabled. + if self.abci_app.synchronized_data.nb_participants: + _logger.error( + f"{exc} This error may occur when the ACN registration has not been successfully performed. " + "Have you set the `share_tm_config_on_startup` flag to `true` in the configuration?" + ) + self._slashing_enabled = False + _logger.warning("Slashing has been disabled!") + + def _try_track_offences( + self, evidences: Evidences, last_commit_info: LastCommitInfo + ) -> None: + """Try to track the offences. If an error occurs, log it, disable slashing, and warn about the latter.""" + try: + if self._slashing_enabled: + # only track offences if the first round has finished + # we avoid tracking offences in the first round + # because we do not have the slashing configuration synced yet + self._track_tm_offences(evidences, last_commit_info) + self._track_app_offences() + except SlashingNotConfiguredError as exc: + self._handle_slashing_not_configured(exc) + + def begin_block( + self, + header: Header, + evidences: Evidences, + last_commit_info: LastCommitInfo, + ) -> None: """Begin block.""" if self.is_finished: raise ABCIAppInternalError( @@ -2796,14 +3520,12 @@ def begin_block(self, header: Header) -> None: self._block_builder.reset() self._block_builder.header = header self.abci_app.update_time(header.timestamp) - # we use the local time of the agent to specify the expiration of the deadline - self._block_stall_deadline = datetime.datetime.now() + datetime.timedelta( - seconds=BLOCKS_STALL_TOLERANCE - ) + self.set_block_stall_deadline() _logger.info( "Created a new local deadline for the next `begin_block` request from the Tendermint node: " f"{self._block_stall_deadline}" ) + self._try_track_offences(evidences, last_commit_info) def deliver_tx(self, transaction: Transaction) -> None: """ @@ -2884,36 +3606,62 @@ def reset_blockchain(self, is_replay: bool = False, is_init: bool = False) -> No ) self._blockchain = Blockchain(is_init=is_init) + def _get_round_result( + self, + ) -> Optional[Tuple[BaseSynchronizedData, Any]]: + """ + Get the round's result. + + Give priority to: + 1. terminating bg rounds + 2. ever running bg rounds + 3. normal bg rounds + 4. normal rounds + + :return: the round's result. + """ + for prioritized_group in self.abci_app.bg_apps_prioritized: + for app in prioritized_group: + result = app.background_round.end_block() + if ( + result is None + or app.type == BackgroundAppType.TERMINATING + and self._terminating_round_called + ): + continue + if ( + app.type == BackgroundAppType.TERMINATING + and not self._terminating_round_called + ): + self._terminating_round_called = True + return result + return self.abci_app.current_round.end_block() + def _update_round(self) -> None: """ Update a round. - Check whether the round has finished. If so, get the - new round and set it as the current round. - """ - background_result: Optional[Tuple[BaseSynchronizedData, Any]] = None - if self.abci_app.is_termination_set: - background_result = self.abci_app.background_round.end_block() - if background_result is not None and not self._termination_called: - # when the background round returns, it takes priority over normal rounds - # because the BackgroundRound never ends, we should only take into account - # its response only once - self._termination_called = True - result: Optional[Tuple[BaseSynchronizedData, Any]] = background_result - else: - result = self.abci_app.current_round.end_block() + Check whether the round has finished. If so, get the new round and set it as the current round. + If a termination app's round has returned a result, then the other apps' rounds are ignored. + """ + result = self._get_round_result() if result is None: - # the termination round, nor the current round returned, so no update needs to be made + # neither the background rounds, nor the current round returned, so no update needs to be made return + if self._slashing_enabled: + self.store_offence_status() + self._last_round_transition_timestamp = self._blockchain.last_block.timestamp self._last_round_transition_height = self.height self._last_round_transition_root_hash = self.root_hash self._last_round_transition_tm_height = self.tm_height + round_result, event = result _logger.debug( - f"updating round, current_round {self.current_round.round_id}, event: {event}, round result {round_result}" + f"updating round, current_round {self.current_round.round_id}, event: {event}, " + f"round result {round_result}" ) self.abci_app.process_event(event, result=round_result) @@ -2924,6 +3672,8 @@ def _reset_to_default_params(self) -> None: self._last_round_transition_root_hash = b"" self._last_round_transition_tm_height = None self._tm_height = None + self._slashing_enabled = False + self.pending_offences = set() def reset_state( self, @@ -2932,19 +3682,20 @@ def reset_state( serialized_db_state: Optional[str] = None, ) -> None: """ - This method resets the state of RoundSequence to the begging of the period. + This method resets the state of RoundSequence to the beginning of the period. - Note: This is intended to be used only for agent <-> tendermint communication recovery only! + Note: This is intended to be used for agent <-> tendermint communication recovery only! - :param restart_from_round: from which round to restart the abci. This round should be the first round in the last period. + :param restart_from_round: from which round to restart the abci. + This round should be the first round in the last period. :param round_count: the round count at the beginning of the period -1. - :param serialized_db_state: the state of the database at the beginning of the period. If provided, the database will be reset to this state. + :param serialized_db_state: the state of the database at the beginning of the period. + If provided, the database will be reset to this state. """ self._reset_to_default_params() self.abci_app.synchronized_data.db.round_count = round_count if serialized_db_state is not None: - self.abci_app.synchronized_data.db.sync(serialized_db_state) - # When the agents prepare the recovery state, their db reflects the state of their last round. + self.sync_db_and_slashing(serialized_db_state) # Furthermore, that hash is then in turn used as the init hash when the tm network is reset. self._last_round_transition_root_hash = self.root_hash @@ -2961,3 +3712,56 @@ def reset_state( f"{set(round_id_to_cls.keys())}." ) self.abci_app.schedule_round(restart_from_round_cls) + + +@dataclass(frozen=True) +class PendingOffencesPayload(BaseTxPayload): + """Represent a transaction payload for pending offences.""" + + accused_agent_address: str + offense_round: int + offense_type_value: int + last_transition_timestamp: float + time_to_live: float + + +class PendingOffencesRound(CollectSameUntilThresholdRound): + """Defines the pending offences background round, which runs concurrently with other rounds to sync the offences.""" + + payload_class = PendingOffencesPayload + synchronized_data_class = BaseSynchronizedData + + def __init__(self, *args: Any, **kwargs: Any) -> None: + """Initialize the `PendingOffencesRound`.""" + super().__init__(*args, **kwargs) + self._latest_round_processed = -1 + + @property + def offence_status(self) -> Dict[str, OffenceStatus]: + """Get the offence status from the round sequence.""" + return self.context.state.round_sequence.offence_status + + def end_block(self) -> None: + """ + Process the end of the block for the pending offences background round. + + It is important to note that this is a non-standard type of round, meaning it does not emit any events. + Instead, it continuously runs in the background. + The objective of this round is to consistently monitor the received pending offences + and achieve a consensus among the agents. + """ + if not self.threshold_reached: + return + + offence = PendingOffense(*self.most_voted_payload_values) + + # an offence should only be tracked once, not every time a payload is processed after the threshold is reached + if self._latest_round_processed == offence.round_count: + return + + # add synchronized offence to the offence status + # only `INVALID_PAYLOAD` offence types are supported at the moment as pending offences: + # https://github.com/valory-xyz/open-autonomy/blob/6831d6ebaf10ea8e3e04624b694c7f59a6d05bb4/packages/valory/skills/abstract_round_abci/handlers.py#L215-L222 # noqa + invalid = offence.offense_type == OffenseType.INVALID_PAYLOAD + self.offence_status[offence.accused_agent_address].invalid_payload.add(invalid) + self._latest_round_processed = offence.round_count diff --git a/packages/valory/skills/abstract_round_abci/behaviour_utils.py b/packages/valory/skills/abstract_round_abci/behaviour_utils.py index 3be5fee9b8..a46ebcf0bd 100644 --- a/packages/valory/skills/abstract_round_abci/behaviour_utils.py +++ b/packages/valory/skills/abstract_round_abci/behaviour_utils.py @@ -78,6 +78,7 @@ BaseTxPayload, LEDGER_API_ADDRESS, OK_CODE, + RoundSequence, Transaction, ) from packages.valory.skills.abstract_round_abci.dialogues import ( @@ -574,6 +575,7 @@ def __init__(self, **kwargs: Any): # pylint: disable=super-init-not-called self._timeout: float = 0 self._is_healthy: bool = False self._non_200_return_code_count: int = 0 + self.gentle_reset_attempted: bool = False @classmethod def auto_behaviour_id(cls) -> str: @@ -598,36 +600,35 @@ def behaviour_id(self) -> str: @property def params(self) -> BaseParams: """Return the params.""" - return cast(BaseParams, self.context.params) + return self.context.params + + @property + def shared_state(self) -> SharedState: + """Return the round sequence.""" + return self.context.state + + @property + def round_sequence(self) -> RoundSequence: + """Return the round sequence.""" + return self.shared_state.round_sequence @property def synchronized_data(self) -> BaseSynchronizedData: """Return the synchronized data.""" - return cast( - BaseSynchronizedData, - cast(SharedState, self.context.state).synchronized_data, - ) + return self.shared_state.synchronized_data @property def tm_communication_unhealthy(self) -> bool: """Return if the Tendermint communication is not healthy anymore.""" - return cast( - SharedState, self.context.state - ).round_sequence.block_stall_deadline_expired + return self.round_sequence.block_stall_deadline_expired def check_in_round(self, round_id: str) -> bool: """Check that we entered a specific round.""" - return ( - cast(SharedState, self.context.state).round_sequence.current_round_id - == round_id - ) + return self.round_sequence.current_round_id == round_id def check_in_last_round(self, round_id: str) -> bool: """Check that we entered a specific round.""" - return ( - cast(SharedState, self.context.state).round_sequence.last_round_id - == round_id - ) + return self.round_sequence.last_round_id == round_id def check_not_in_round(self, round_id: str) -> bool: """Check that we are not in a specific round.""" @@ -643,10 +644,7 @@ def check_round_has_finished(self, round_id: str) -> bool: def check_round_height_has_changed(self, round_height: int) -> bool: """Check that the round height has changed.""" - return ( - cast(SharedState, self.context.state).round_sequence.current_round_height - != round_height - ) + return self.round_sequence.current_round_height != round_height def is_round_ended(self, round_id: str) -> Callable[[], bool]: """Get a callable to check whether the current round has ended.""" @@ -662,12 +660,11 @@ def wait_until_round_end( :yield: None """ round_id = self.matching_round.auto_round_id() - round_height = cast( - SharedState, self.context.state - ).round_sequence.current_round_height + round_height = self.round_sequence.current_round_height if self.check_not_in_round(round_id) and self.check_not_in_last_round(round_id): raise ValueError( - f"Should be in matching round ({round_id}) or last round ({self.context.state.round_sequence.last_round_id}), actual round {self.context.state.round_sequence.current_round_id}!" + f"Should be in matching round ({round_id}) or last round ({self.round_sequence.last_round_id}), " + f"actual round {self.round_sequence.current_round_id}!" ) yield from self.wait_for_condition( partial(self.check_round_height_has_changed, round_height), timeout=timeout @@ -686,9 +683,9 @@ def wait_from_last_timestamp(self, seconds: float) -> Any: """ if seconds < 0: raise ValueError("Can only wait for a positive amount of time") - deadline = cast( - SharedState, self.context.state - ).round_sequence.abci_app.last_timestamp + datetime.timedelta(seconds=seconds) + deadline = self.round_sequence.abci_app.last_timestamp + datetime.timedelta( + seconds=seconds + ) def _wait_until() -> bool: return datetime.datetime.now() > deadline @@ -714,9 +711,7 @@ def send_a2a_transaction( :yield: the responses """ stop_condition = self.is_round_ended(self.matching_round.auto_round_id()) - round_count = cast( - SharedState, self.context.state - ).synchronized_data.round_count + round_count = self.synchronized_data.round_count object.__setattr__(payload, "round_count", round_count) yield from self._send_transaction( payload, @@ -730,7 +725,7 @@ def async_act_wrapper(self) -> Generator: self._log_start() self._is_started = True try: - if self.context.state.round_sequence.syncing_up: + if self.round_sequence.syncing_up: yield from self._check_sync() else: yield from self.async_act() @@ -758,13 +753,17 @@ def _check_sync( remote_height = int( json_body["result"]["sync_info"]["latest_block_height"] ) - local_height = int(self.context.state.round_sequence.height) + local_height = int(self.round_sequence.height) _is_sync_complete = local_height == remote_height if _is_sync_complete: self.context.logger.info( f"local height == remote == {local_height}; Sync complete..." ) - self.context.state.round_sequence.end_sync() + self.round_sequence.end_sync() + # we set the block stall deadline here because we pinged the /status endpoint + # and received a response from tm, which means that the communication is fine + self.round_sequence.set_block_stall_deadline() + self.gentle_reset_attempted = False return yield from self.sleep(self.context.params.tendermint_check_sleep_delay) except (json.JSONDecodeError, KeyError): # pragma: nocover @@ -1028,6 +1027,8 @@ def _send_transaction_request( signing_msg: SigningMessage, use_flashbots: bool = False, target_block_numbers: Optional[List[int]] = None, + chain_id: Optional[str] = None, + raise_on_failed_simulation: bool = False, ) -> None: """ Send transaction request. @@ -1040,6 +1041,8 @@ def _send_transaction_request( :param signing_msg: signing message :param use_flashbots: whether to use flashbots for the transaction or not :param target_block_numbers: the target block numbers in case we are using flashbots + :param chain_id: the chain name to use for the ledger call + :param raise_on_failed_simulation: whether to raise an exception if the simulation fails or not. """ ledger_api_dialogues = cast( LedgerApiDialogues, self.context.ledger_api_dialogues @@ -1051,10 +1054,18 @@ def _send_transaction_request( counterparty=LEDGER_API_ADDRESS, performative=LedgerApiMessage.Performative.SEND_SIGNED_TRANSACTION, ) + if chain_id: + kwargs = LedgerApiMessage.Kwargs({"chain_id": chain_id}) + create_kwargs.update(dict(kwargs=kwargs)) + if use_flashbots: - kwargs = {} + _kwargs = { + "chain_id": chain_id, + "raise_on_failed_simulation": raise_on_failed_simulation, + "use_all_builders": True, # TODO: make this a proper parameter + } if target_block_numbers is not None: - kwargs["target_block_numbers"] = target_block_numbers + _kwargs["target_block_numbers"] = target_block_numbers # type: ignore create_kwargs.update( dict( performative=LedgerApiMessage.Performative.SEND_SIGNED_TRANSACTIONS, @@ -1063,7 +1074,7 @@ def _send_transaction_request( ledger_id=FLASHBOTS_LEDGER_ID, signed_transactions=[signing_msg.signed_transaction.body], ), - kwargs=LedgerApiMessage.Kwargs(kwargs), + kwargs=LedgerApiMessage.Kwargs(_kwargs), ) ) else: @@ -1082,7 +1093,7 @@ def _send_transaction_request( request_nonce ] = self.get_callback_request() self.context.outbox.put_message(message=ledger_api_msg) - self.context.logger.info("sending transaction to ledger.") + self.context.logger.info("Sending transaction to ledger.") def _send_transaction_receipt_request( self, @@ -1498,6 +1509,8 @@ def send_raw_transaction( transaction: RawTransaction, use_flashbots: bool = False, target_block_numbers: Optional[List[int]] = None, + raise_on_failed_simulation: bool = False, + chain_id: Optional[str] = None, ) -> Generator[ None, Union[None, SigningMessage, LedgerApiMessage], @@ -1519,11 +1532,16 @@ def send_raw_transaction( :param transaction: transaction data :param use_flashbots: whether to use flashbots for the transaction or not :param target_block_numbers: the target block numbers in case we are using flashbots + :param raise_on_failed_simulation: whether to raise an exception if the transaction fails the simulation or not + :param chain_id: the chain name to use for the ledger call :yield: SigningMessage object :return: transaction hash """ + if chain_id is None: + chain_id = self.params.default_chain_id + terms = Terms( - self.context.default_ledger_id, + chain_id, self.context.agent_address, counterparty_address="", amount_by_currency_id={}, @@ -1531,7 +1549,7 @@ def send_raw_transaction( nonce="", ) self.context.logger.info( - f"Sending signing request for transaction: {transaction}..." + f"Sending signing request to ledger '{chain_id}' for transaction: {transaction}..." ) self._send_transaction_signing_request(transaction, terms) signature_response = yield from self.wait_for_message() @@ -1547,7 +1565,11 @@ def send_raw_transaction( f"Received signature response: {signature_response}\n Sending transaction..." ) self._send_transaction_request( - signature_response, use_flashbots, target_block_numbers + signature_response, + use_flashbots, + target_block_numbers, + chain_id, + raise_on_failed_simulation, ) transaction_digest_msg = yield from self.wait_for_message() transaction_digest_msg = cast(LedgerApiMessage, transaction_digest_msg) @@ -1733,9 +1755,7 @@ def _acn_request_from_pending( """Perform an ACN request to each one of the agents which have not sent a response yet.""" not_responded_yet = { address - for address, deliverable in cast( - SharedState, self.context.state - ).address_to_acn_deliverable.items() + for address, deliverable in self.shared_state.address_to_acn_deliverable.items() if deliverable is None } @@ -1767,9 +1787,8 @@ def _perform_acn_request( :param performative: the ACN request performative. :return: the result that the majority of the agents sent. If majority cannot be reached, returns `None`. """ - shared_state = cast(SharedState, self.context.state) # reset the ACN deliverables at the beginning of a new request - shared_state.address_to_acn_deliverable = shared_state.acn_container() + self.shared_state.address_to_acn_deliverable = self.shared_state.acn_container() result = None for i in range(self.params.max_attempts): @@ -1778,7 +1797,7 @@ def _perform_acn_request( ) yield from self._acn_request_from_pending(performative) - result = cast(SharedState, self.context.state).get_acn_result() + result = self.shared_state.get_acn_result() if result is not None: break @@ -1800,7 +1819,7 @@ def request_recovery_params(self) -> Generator[None, None, bool]: ) return False - cast(SharedState, self.context.state).tm_recovery_params = acn_result + self.shared_state.tm_recovery_params = acn_result self.context.logger.info( f"Updated the Tendermint recovery parameters from the other agents via the ACN: {acn_result}" ) @@ -1869,7 +1888,7 @@ def _get_reset_params(self, default: bool) -> Optional[Dict[str, str]]: return None last_round_transition_timestamp = ( - self.context.state.round_sequence.last_round_transition_timestamp + self.round_sequence.last_round_transition_timestamp ) genesis_time = last_round_transition_timestamp.astimezone(pytz.UTC).strftime( GENESIS_TIME_FMT @@ -1903,8 +1922,8 @@ def reset_tendermint_with_wait( # pylint: disable=too-many-locals, too-many-sta f"Resetting tendermint node at end of period={self.synchronized_data.period_count}." ) - backup_blockchain = self.context.state.round_sequence.blockchain - self.context.state.round_sequence.reset_blockchain() + backup_blockchain = self.round_sequence.blockchain + self.round_sequence.reset_blockchain() reset_params = self._get_reset_params(on_startup) request_message, http_dialogue = self._build_http_request_message( "GET", @@ -1920,7 +1939,7 @@ def reset_tendermint_with_wait( # pylint: disable=too-many-locals, too-many-sta is_replay = response.get("is_replay", False) if is_replay: # in case of replay, the local blockchain should be set up differently. - self.context.state.round_sequence.reset_blockchain( + self.round_sequence.reset_blockchain( is_replay=is_replay, is_init=True ) for handler_name in self.context.handlers.__dict__.keys(): @@ -1930,18 +1949,17 @@ def reset_tendermint_with_wait( # pylint: disable=too-many-locals, too-many-sta # in case of successful reset we store the reset params in the shared state, # so that in the future if the communication with tendermint breaks, and we need to # perform a hard reset to restore it, we can use these as the right ones - shared_state = cast(SharedState, self.context.state) - round_count = shared_state.synchronized_data.db.round_count - 1 + round_count = self.synchronized_data.db.round_count - 1 # in case we need to reset in order to recover agent <-> tm communication # we store this round as the one to start from restart_from_round = self.matching_round - shared_state.tm_recovery_params = TendermintRecoveryParams( + self.shared_state.tm_recovery_params = TendermintRecoveryParams( reset_params=reset_params, round_count=round_count, reset_from_round=restart_from_round.auto_round_id(), - serialized_db_state=shared_state.synchronized_data.db.serialize(), + serialized_db_state=self.shared_state.synchronized_data.db.serialize(), ) - self.context.state.round_sequence.abci_app.cleanup( + self.round_sequence.abci_app.cleanup( self.params.cleanup_history_depth, self.params.cleanup_history_depth_current, ) @@ -1949,7 +1967,7 @@ def reset_tendermint_with_wait( # pylint: disable=too-many-locals, too-many-sta else: msg = response.get("message") - self.context.state.round_sequence.blockchain = backup_blockchain + self.round_sequence.blockchain = backup_blockchain self.context.logger.error(f"Error resetting: {msg}") yield from self.sleep(self.params.sleep_time) return False @@ -1957,7 +1975,7 @@ def reset_tendermint_with_wait( # pylint: disable=too-many-locals, too-many-sta self.context.logger.error( "Error communicating with tendermint com server." ) - self.context.state.round_sequence.blockchain = backup_blockchain + self.round_sequence.blockchain = backup_blockchain yield from self.sleep(self.params.sleep_time) return False @@ -1972,7 +1990,7 @@ def reset_tendermint_with_wait( # pylint: disable=too-many-locals, too-many-sta return False remote_height = int(json_body["result"]["sync_info"]["latest_block_height"]) - local_height = self.context.state.round_sequence.height + local_height = self.round_sequence.height self.context.logger.info( "local-height = %s, remote-height=%s", local_height, remote_height ) @@ -1988,6 +2006,7 @@ def reset_tendermint_with_wait( # pylint: disable=too-many-locals, too-many-sta # if we are on startup we don't need to wait for the reset pause duration # as the reset is being performed to update the tm config. yield from self.wait_from_last_timestamp(self.hard_reset_sleep) + self._is_healthy = False return True def send_to_ipfs( # pylint: disable=too-many-arguments @@ -2129,24 +2148,14 @@ def hard_reset_sleep(self) -> float: """ return self._hard_reset_sleep - def _kill_if_no_majority_peers(self) -> Generator[None, None, None]: - """This method checks whether there are enough peers in the network to reach majority. If not, the agent is shut down.""" - # We assign a timeout to the num_active_peers request because we are trying to check whether the unhealthy - # tm communication, i.e. tm not sending blocks to the abci (agent), is caused by not having enough peers - # in the network. If that's the case, the node that is being queried has to be healthy, and respond in a - # timely fashion. If the tm node doesn't respond in the specified timeout, we assume the problem is not - # the lack of peers in the service. - num_active_peers = yield from self.num_active_peers(timeout=TM_REQ_TIMEOUT) - if ( - num_active_peers is not None - and num_active_peers < self.synchronized_data.consensus_threshold - ): - self.context.logger.error( - f"There should be at least {self.synchronized_data.consensus_threshold} peers in the service," - f" only {num_active_peers} are currently active. Shutting down the agent." - ) - not_ok_code = 1 - sys.exit(not_ok_code) + def _gentle_reset(self) -> Generator[None, None, None]: + """Perform a gentle reset of the Tendermint node.""" + self.context.logger.info("Performing a gentle reset.") + request_message, http_dialogue = self._build_http_request_message( + "GET", + self.params.tendermint_com_url + "/gentle_reset", + ) + yield from self._do_request(request_message, http_dialogue) def _handle_unhealthy_tm(self) -> Generator: """This method handles the case when the tendermint node is unhealthy.""" @@ -2155,12 +2164,14 @@ def _handle_unhealthy_tm(self) -> Generator: "Trying to reset local Tendermint node as there could be something wrong with the communication." ) - # we first check whether the reason why we haven't received blocks for more than we allow is because - # there are not enough peers in the network to reach majority. - yield from self._kill_if_no_majority_peers() + if not self.gentle_reset_attempted: + self.gentle_reset_attempted = True + yield from self._gentle_reset() + yield from self._check_sync() + return - # since we have reached this point that means that the cause of blocks not being received - # cannot be attributed to a lack of peers in the network + # since we have reached this point, that means that the cause of blocks not being received + # cannot be fixed with a simple gentle reset, # therefore, we request the recovery parameters via the ACN, and if we succeed, we use them to recover acn_communication_success = yield from self.request_recovery_params() if not acn_communication_success: @@ -2169,9 +2180,8 @@ def _handle_unhealthy_tm(self) -> Generator: ) return - shared_state = cast(SharedState, self.context.state) - recovery_params = shared_state.tm_recovery_params - shared_state.round_sequence.reset_state( + recovery_params = self.shared_state.tm_recovery_params + self.round_sequence.reset_state( restart_from_round=recovery_params.reset_from_round, round_count=recovery_params.round_count, serialized_db_state=recovery_params.serialized_db_state, @@ -2183,9 +2193,7 @@ def _handle_unhealthy_tm(self) -> Generator: is_recovery=True, ) if reset_successfully: - self.context.logger.info( - "Tendermint reset was successfully performed. " - ) + self.context.logger.info("Tendermint reset was successfully performed.") # we sleep to give some time for tendermint to start sending us blocks # otherwise we might end-up assuming that tendermint is still not working. # Note that the wait_from_last_timestamp() in reset_tendermint_with_wait() @@ -2209,10 +2217,7 @@ def _get_reset_params(self, default: bool) -> Optional[Dict[str, str]]: # we get the params from the latest successful reset, if they are not available, # i.e. no successful reset has been performed, we return None. # Returning None means default params will be used. - reset_params = cast( - SharedState, self.context.state - ).tm_recovery_params.reset_params - return reset_params + return self.shared_state.tm_recovery_params.reset_params def get_callback_request(self) -> Callable[[Message, "BaseBehaviour"], None]: """Wrapper for callback_request(), overridden to remove checks not applicable to TmManager.""" diff --git a/packages/valory/skills/abstract_round_abci/behaviours.py b/packages/valory/skills/abstract_round_abci/behaviours.py index 5cc6e8221f..ac34599f90 100644 --- a/packages/valory/skills/abstract_round_abci/behaviours.py +++ b/packages/valory/skills/abstract_round_abci/behaviours.py @@ -18,9 +18,23 @@ # ------------------------------------------------------------------------------ """This module contains the behaviours for the 'abstract_round_abci' skill.""" + from abc import ABC, ABCMeta from collections import defaultdict -from typing import AbstractSet, Any, Dict, Generic, List, Optional, Tuple, Type, cast +from dataclasses import asdict +from typing import ( + AbstractSet, + Any, + Dict, + Generator, + Generic, + List, + Optional, + Set, + Tuple, + Type, + cast, +) from aea.skills.base import Behaviour @@ -29,12 +43,21 @@ AbciApp, AbstractRound, EventType, + PendingOffencesPayload, + PendingOffencesRound, + PendingOffense, + RoundSequence, ) from packages.valory.skills.abstract_round_abci.behaviour_utils import ( BaseBehaviour, TmManager, make_degenerate_behaviour, ) +from packages.valory.skills.abstract_round_abci.models import SharedState + + +SLASHING_BACKGROUND_BEHAVIOUR_ID = "slashing_check_behaviour" +TERMINATION_BACKGROUND_BEHAVIOUR_ID = "background_behaviour" BehaviourType = Type[BaseBehaviour] @@ -45,6 +68,8 @@ class _MetaRoundBehaviour(ABCMeta): """A metaclass that validates AbstractRoundBehaviour's attributes.""" + are_background_behaviours_set: bool = False + def __new__(mcs, name: str, bases: Tuple, namespace: Dict, **kwargs: Any) -> Type: # type: ignore """Initialize the class.""" new_cls = super().__new__(mcs, name, bases, namespace, **kwargs) @@ -56,6 +81,9 @@ def __new__(mcs, name: str, bases: Tuple, namespace: Dict, **kwargs: Any) -> Typ # the check only applies to AbstractRoundBehaviour subclasses return new_cls + mcs.are_background_behaviours_set = bool( + new_cls.background_behaviours_cls - {PendingOffencesBehaviour} + ) mcs._check_consistency(cast(AbstractRoundBehaviour, new_cls)) return new_cls @@ -73,9 +101,9 @@ def _check_all_required_classattributes_are_set( ) -> None: """Check that all the required class attributes are set.""" try: - behaviour_cls.abci_app_cls # pylint: disable=pointless-statement - behaviour_cls.behaviours # pylint: disable=pointless-statement - behaviour_cls.initial_behaviour_cls # pylint: disable=pointless-statement + _ = behaviour_cls.abci_app_cls + _ = behaviour_cls.behaviours + _ = behaviour_cls.initial_behaviour_cls except AttributeError as e: raise ABCIAppInternalError(*e.args) from None @@ -105,10 +133,15 @@ def _check_matching_round_consistency( mcs, behaviour_cls: "AbstractRoundBehaviour" ) -> None: """Check that matching rounds are: (1) unique across behaviour, and (2) covering.""" + matching_bg_round_classes = { + behaviour_cls.matching_round + for behaviour_cls in behaviour_cls.background_behaviours_cls + } round_to_behaviour: Dict[Type[AbstractRound], List[BehaviourType]] = { round_cls: [] for round_cls in behaviour_cls.abci_app_cls.get_all_round_classes( - behaviour_cls.is_background_behaviour_set + matching_bg_round_classes, + mcs.are_background_behaviours_set, ) } @@ -148,7 +181,61 @@ def _check_initial_behaviour_in_set_of_behaviours( ) -class AbstractRoundBehaviour( +class PendingOffencesBehaviour(BaseBehaviour): + """A behaviour responsible for checking whether there are any pending offences.""" + + matching_round = PendingOffencesRound + + @property + def round_sequence(self) -> RoundSequence: + """Get the round sequence from the shared state.""" + return cast(SharedState, self.context.state).round_sequence + + @property + def pending_offences(self) -> Set[PendingOffense]: + """Get the pending offences from the round sequence.""" + return self.round_sequence.pending_offences + + def has_pending_offences(self) -> bool: + """Check if there are any pending offences.""" + return bool(len(self.pending_offences)) + + def async_act(self) -> Generator: + """ + Checks the pending offences. + + This behaviour simply checks if the set of pending offences is not empty. + When it’s not empty, it pops the offence from the set, and sends it to the rest of the agents via a payload + + :return: None + :yield: None + """ + yield from self.wait_for_condition(self.has_pending_offences) + offence = self.pending_offences.pop() + offence_detected_log = ( + f"An offence of type {offence.offense_type.name} has been detected " + f"for agent with address {offence.accused_agent_address} during round {offence.round_count}. " + ) + offence_expiration = offence.last_transition_timestamp + offence.time_to_live + last_timestamp = self.round_sequence.last_round_transition_timestamp + + if offence_expiration < last_timestamp.timestamp(): + ignored_log = "Offence will be ignored as it has expired." + self.context.logger.info(offence_detected_log + ignored_log) + return + + sharing_log = "Sharing offence with the other agents." + self.context.logger.info(offence_detected_log + sharing_log) + + payload = PendingOffencesPayload( + self.context.agent_address, *asdict(offence).values() + ) + yield from self.send_a2a_transaction(payload) + yield from self.wait_until_round_end() + self.set_done() + + +class AbstractRoundBehaviour( # pylint: disable=too-many-instance-attributes Behaviour, ABC, Generic[EventType], metaclass=_MetaRoundBehaviour ): """This behaviour implements an abstract round behaviour.""" @@ -156,7 +243,7 @@ class AbstractRoundBehaviour( abci_app_cls: Type[AbciApp[EventType]] behaviours: AbstractSet[BehaviourType] initial_behaviour_cls: BehaviourType - background_behaviour_cls: Optional[BehaviourType] = None + background_behaviours_cls: Set[BehaviourType] = {PendingOffencesBehaviour} # type: ignore def __init__(self, **kwargs: Any) -> None: """Initialize the behaviour.""" @@ -169,7 +256,7 @@ def __init__(self, **kwargs: Any) -> None: ] = self._get_round_to_behaviour_mapping(self.behaviours) self.current_behaviour: Optional[BaseBehaviour] = None - self.background_behaviour: Optional[BaseBehaviour] = None + self.background_behaviours: Set[BaseBehaviour] = set() self.tm_manager: Optional[TmManager] = None # keep track of last round height so to detect changes self._last_round_height = 0 @@ -223,10 +310,29 @@ def instantiate_behaviour_cls(self, behaviour_cls: BehaviourType) -> BaseBehavio name=behaviour_cls.auto_behaviour_id(), skill_context=self.context ) - @property - def is_background_behaviour_set(self) -> bool: - """Returns whether the background behaviour is set.""" - return self.background_behaviour_cls is not None + def _setup_background(self) -> None: + """Set up the background behaviours.""" + params = cast(BaseBehaviour, self.current_behaviour).params + for background_cls in self.background_behaviours_cls: + background_cls = cast(Type[BaseBehaviour], background_cls) + + if ( + not params.use_termination + and background_cls.auto_behaviour_id() + == TERMINATION_BACKGROUND_BEHAVIOUR_ID + ) or ( + not params.use_slashing + and background_cls.auto_behaviour_id() + == SLASHING_BACKGROUND_BEHAVIOUR_ID + or background_cls == PendingOffencesBehaviour + ): + # comparing with the behaviour id is not entirely safe, as there is a potential for conflicts + # if a user creates a behaviour with the same name + continue + + self.background_behaviours.add( + self.instantiate_behaviour_cls(background_cls) + ) def setup(self) -> None: """Set up the behaviours.""" @@ -234,20 +340,16 @@ def setup(self) -> None: self.initial_behaviour_cls ) self.tm_manager = self.instantiate_behaviour_cls(TmManager) # type: ignore - if ( - self.is_background_behaviour_set - and self.current_behaviour.params.use_termination - ): - self.background_behaviour_cls = cast( - Type[BaseBehaviour], self.background_behaviour_cls - ) - self.background_behaviour = self.instantiate_behaviour_cls( - self.background_behaviour_cls - ) + self._setup_background() def teardown(self) -> None: """Tear down the behaviour""" + def _background_act(self) -> None: + """Call the act wrapper for the background behaviours.""" + for behaviour in self.background_behaviours: + behaviour.act_wrapper() + def act(self) -> None: """Implement the behaviour.""" tm_manager = cast(TmManager, self.tm_manager) @@ -268,8 +370,7 @@ def act(self) -> None: self.current_behaviour.clean_up() self.current_behaviour = None - if self.background_behaviour is not None: - self.background_behaviour.act_wrapper() + self._background_act() def _process_current_round(self) -> None: """Process current ABCIApp round.""" diff --git a/packages/valory/skills/abstract_round_abci/handlers.py b/packages/valory/skills/abstract_round_abci/handlers.py index f46c87e095..6bc5be8639 100644 --- a/packages/valory/skills/abstract_round_abci/handlers.py +++ b/packages/valory/skills/abstract_round_abci/handlers.py @@ -18,9 +18,11 @@ # ------------------------------------------------------------------------------ """This module contains the handler for the 'abstract_round_abci' skill.""" + import ipaddress import json from abc import ABC +from calendar import timegm from dataclasses import asdict from enum import Enum from typing import Any, Callable, Dict, FrozenSet, List, Optional, cast @@ -46,9 +48,12 @@ from packages.valory.skills.abstract_round_abci.base import ( ABCIAppInternalError, AddBlockError, + DEFAULT_PENDING_OFFENCE_TTL, ERROR_CODE, LateArrivingTransaction, OK_CODE, + OffenseType, + PendingOffense, SignatureNotValidError, Transaction, TransactionNotValidError, @@ -73,9 +78,7 @@ class ABCIRoundHandler(ABCIHandler): SUPPORTED_PROTOCOL = AbciMessage.protocol_id - def info( # pylint: disable=no-self-use,useless-super-delegation - self, message: AbciMessage, dialogue: AbciDialogue - ) -> AbciMessage: + def info(self, message: AbciMessage, dialogue: AbciDialogue) -> AbciMessage: """ Handle the 'info' request. @@ -143,16 +146,14 @@ def init_chain(self, message: AbciMessage, dialogue: AbciDialogue) -> AbciMessag ) return cast(AbciMessage, reply) - def begin_block( # pylint: disable=no-self-use - self, message: AbciMessage, dialogue: AbciDialogue - ) -> AbciMessage: + def begin_block(self, message: AbciMessage, dialogue: AbciDialogue) -> AbciMessage: """Handle the 'begin_block' request.""" - cast(SharedState, self.context.state).round_sequence.begin_block(message.header) + cast(SharedState, self.context.state).round_sequence.begin_block( + message.header, message.byzantine_validators, message.last_commit_info + ) return super().begin_block(message, dialogue) - def check_tx( # pylint: disable=no-self-use - self, message: AbciMessage, dialogue: AbciDialogue - ) -> AbciMessage: + def check_tx(self, message: AbciMessage, dialogue: AbciDialogue) -> AbciMessage: """Handle the 'check_tx' request.""" transaction_bytes = message.tx # check we can decode the transaction @@ -190,23 +191,56 @@ def check_tx( # pylint: disable=no-self-use ) return cast(AbciMessage, reply) - def deliver_tx( # pylint: disable=no-self-use - self, message: AbciMessage, dialogue: AbciDialogue - ) -> AbciMessage: + def settle_pending_offence( + self, accused_agent_address: Optional[str], invalid: bool + ) -> None: + """Add an invalid pending offence or a no-offence for the given accused agent address, if possible.""" + if accused_agent_address is None: + # only add the offence if we know and can verify the sender, + # otherwise someone could pretend to be someone else, which may lead to wrong punishments + return + + round_sequence = cast(SharedState, self.context.state).round_sequence + + try: + last_round_transition_timestamp = timegm( + round_sequence.last_round_transition_timestamp.utctimetuple() + ) + except ValueError: # pragma: no cover + # do not add an offence if no round transition has been completed yet + return + + offence_type = ( + OffenseType.INVALID_PAYLOAD if invalid else OffenseType.NO_OFFENCE + ) + pending_offense = PendingOffense( + accused_agent_address, + round_sequence.current_round_height, + offence_type, + last_round_transition_timestamp, + DEFAULT_PENDING_OFFENCE_TTL, + ) + round_sequence.add_pending_offence(pending_offense) + + def deliver_tx(self, message: AbciMessage, dialogue: AbciDialogue) -> AbciMessage: """Handle the 'deliver_tx' request.""" transaction_bytes = message.tx - shared_state = cast(SharedState, self.context.state) + round_sequence = cast(SharedState, self.context.state).round_sequence + payload_sender: Optional[str] = None try: transaction = Transaction.decode(transaction_bytes) transaction.verify(self.context.default_ledger_id) - shared_state.round_sequence.check_is_finished() - shared_state.round_sequence.deliver_tx(transaction) + payload_sender = transaction.payload.sender + round_sequence.check_is_finished() + round_sequence.deliver_tx(transaction) except ( SignatureNotValidError, TransactionNotValidError, TransactionTypeNotRecognizedError, ) as exception: self._log_exception(exception) + # the transaction is invalid, it's potentially an offence, so we add it to the list of pending offences + self.settle_pending_offence(payload_sender, invalid=True) return self._deliver_tx_failed( message, dialogue, exception_to_info_msg(exception) ) @@ -216,6 +250,9 @@ def deliver_tx( # pylint: disable=no-self-use message, dialogue, exception_to_info_msg(exception) ) + # the invalid payloads' availability window needs to be populated with the negative values as well + self.settle_pending_offence(payload_sender, invalid=False) + # return deliver_tx success reply = dialogue.reply( performative=AbciMessage.Performative.RESPONSE_DELIVER_TX, @@ -231,17 +268,13 @@ def deliver_tx( # pylint: disable=no-self-use ) return cast(AbciMessage, reply) - def end_block( # pylint: disable=no-self-use - self, message: AbciMessage, dialogue: AbciDialogue - ) -> AbciMessage: + def end_block(self, message: AbciMessage, dialogue: AbciDialogue) -> AbciMessage: """Handle the 'end_block' request.""" self.context.state.round_sequence.tm_height = message.height cast(SharedState, self.context.state).round_sequence.end_block() return super().end_block(message, dialogue) - def commit( # pylint: disable=no-self-use - self, message: AbciMessage, dialogue: AbciDialogue - ) -> AbciMessage: + def commit(self, message: AbciMessage, dialogue: AbciDialogue) -> AbciMessage: """ Handle the 'commit' request. diff --git a/packages/valory/skills/abstract_round_abci/models.py b/packages/valory/skills/abstract_round_abci/models.py index 6c6d38da47..e35143b15e 100644 --- a/packages/valory/skills/abstract_round_abci/models.py +++ b/packages/valory/skills/abstract_round_abci/models.py @@ -17,7 +17,7 @@ # # ------------------------------------------------------------------------------ -"""This module contains the shared state for the price estimation ABCI application.""" +"""This module contains the core models for all the ABCI apps.""" import inspect import json @@ -49,6 +49,7 @@ AbciApp, AbciAppDB, BaseSynchronizedData, + OffenceStatus, ROUND_COUNT_DEFAULT, RoundSequence, VALUE_NOT_PROVIDED, @@ -67,6 +68,7 @@ NUMBER_OF_RETRIES: int = 5 DEFAULT_BACKOFF_FACTOR: float = 2.0 DEFAULT_TYPE_NAME: str = "str" +DEFAULT_CHAIN = "ethereum" class FrozenMixin: # pylint: disable=too-few-public-methods @@ -303,7 +305,22 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: ) self.tendermint_p2p_url: str = self._ensure("tendermint_p2p_url", kwargs, str) self.use_termination: bool = self._ensure("use_termination", kwargs, bool) + self.use_slashing: bool = self._ensure("use_slashing", kwargs, bool) + self.slash_cooldown_hours: int = self._ensure( + "slash_cooldown_hours", kwargs, int + ) + self.slash_threshold_amount: int = self._ensure( + "slash_threshold_amount", kwargs, int + ) + self.light_slash_unit_amount: int = self._ensure( + "light_slash_unit_amount", kwargs, int + ) + self.serious_slash_unit_amount: int = self._ensure( + "serious_slash_unit_amount", kwargs, int + ) self.setup_params: Dict[str, Any] = self._ensure("setup", kwargs, dict) + # TODO add to all configs + self.default_chain_id: str = kwargs.get("default_chain_id", DEFAULT_CHAIN) # we sanitize for null values as these are just kept for schema definitions skill_id = kwargs["skill_context"].skill_id @@ -427,6 +444,50 @@ def __init__( kwargs["skill_context"] = skill_context super().__init__(*args, **kwargs) + def setup_slashing(self, validator_to_agent: Dict[str, str]) -> None: + """Initialize the structures required for slashing.""" + configured_agents = set(self.initial_tm_configs.keys()) + agents_mapped = set(validator_to_agent.values()) + diff = agents_mapped.symmetric_difference(configured_agents) + if diff: + raise ValueError( + f"Trying to use the mapping `{validator_to_agent}`, which contains validators for non-configured " + "agents and/or does not contain validators for some configured agents. " + f"The agents which have been configured via ACN are `{configured_agents}` and the diff was for {diff}." + ) + self.round_sequence.validator_to_agent = validator_to_agent + self.round_sequence.offence_status = { + agent: OffenceStatus() for agent in agents_mapped + } + + def get_validator_address(self, agent_address: str) -> str: + """Get the validator address of an agent.""" + if agent_address not in self.synchronized_data.all_participants: + raise ValueError( + f"The validator address of non-participating agent `{agent_address}` was requested." + ) + + try: + agent_config = self.initial_tm_configs[agent_address] + except KeyError as e: + raise ValueError( + "SharedState's setup was not performed successfully." + ) from e + + if agent_config is None: + raise ValueError( + f"ACN registration has not been successfully performed for agent `{agent_address}`. " + "Have you set the `share_tm_config_on_startup` flag to `true` in the configuration?" + ) + + validator_address = agent_config.get("address", None) + if validator_address is None: + raise ValueError( + f"The tendermint configuration for agent `{agent_address}` is invalid: `{agent_config}`." + ) + + return validator_address + def acn_container(self) -> Dict[str, Any]: """Create a container for ACN results, i.e., a mapping from others' addresses to `None`.""" ourself = {self.context.agent_address} @@ -436,7 +497,7 @@ def acn_container(self) -> Dict[str, Any]: def setup(self) -> None: """Set up the model.""" - self._round_sequence = RoundSequence(self.abci_app_cls) + self._round_sequence = RoundSequence(self.context, self.abci_app_cls) setup_params = cast(BaseParams, self.context.params).setup_params self.round_sequence.setup( BaseSynchronizedData( diff --git a/packages/valory/skills/abstract_round_abci/skill.yaml b/packages/valory/skills/abstract_round_abci/skill.yaml index 248ad7e81c..1bc4b08b15 100644 --- a/packages/valory/skills/abstract_round_abci/skill.yaml +++ b/packages/valory/skills/abstract_round_abci/skill.yaml @@ -7,28 +7,28 @@ license: Apache-2.0 aea_version: '>=1.0.0, <2.0.0' fingerprint: README.md: bafybeievb7bhfm46p5adx3x4gvsynjpq35fcrrapzn5m2whcdt4ufxfvfq - __init__.py: bafybeicjyrltgdmwzvctebhfteyyd5mbrjashiji4glwf5vwcijuyzzm24 - abci_app_chain.py: bafybeic6uzd7oywbnhoqrv5bitan2kw7sgfejgnmjbe5sobvckvk2qisvm - base.py: bafybeigfursyityrz4brtl475qb767c4qhzmzzya56l5tamje3dz5ybrsy - behaviour_utils.py: bafybeidan3bdtejaly4almhl5jly5ec2jouwqk4uny2iqqn6umj3et6owu - behaviours.py: bafybeiaurunqjfmh7gxgnphxhibfrhn4g6sx6gfjpnlk5rl6e2lqxxjwbm + __init__.py: bafybeibc6jsxgjjteyocsu45hu754dc2aqf5dc5bj7qyogx64ogg7qz7ni + abci_app_chain.py: bafybeiflgwhyzkoqpgrvx3eol6p37l6jymccfqgz4hs35gh7zuptvetmh4 + base.py: bafybeifi7vzso5qzcb7g65qen2uqz7ixy4okywdranhiuocwzi4i62ol3a + behaviour_utils.py: bafybeigfk3s27iyeuvt2c7iw6bgico6sur3e22w3xvm7n6nywsm4ic2u4y + behaviours.py: bafybeic7rnt4fo3falirgepw4akun5xh3mna7didul6daitlk5xwsza7lm common.py: bafybeidzqdfvwf226d5qeqcyzpkqsjy6kiawoz5ldsfvzzhtym3f73giia dialogues.py: bafybeid5sgrfa7ghnnjpssltgtey5gzt5kc2jlaitffaukvhhdbhrzcjti - handlers.py: bafybeihivgv6caywexg3h32d4mzvnulvxlvgda6r2k5pjvezmsaxjs35qq + handlers.py: bafybeid4nt54j7dijzsiu7kdau6bavdkg72pgjr3lyuzb54a6m5kumqhma io_/__init__.py: bafybeihv6ytxeo5jkbdlqjum4pfo4aaluvw4m7c55k5xncvvs7ubrlokhy io_/ipfs.py: bafybeiffdxdt36rcwu5tyfav2umvw3hvlfjwbys3626p2g2gdlfi7djzly io_/load.py: bafybeigkywwlsheqvd4gpyfwaxqzkkb2ih2poyicqk7e7n2mrsghxzyns4 io_/paths.py: bafybeicfno2l4vwtmjcm3rzpp6tqi3xlkof47pypf5teecad22d44u2ple io_/store.py: bafybeig24lslvhf7amim55ig5zzre4z45pcx3r2ozlagg3mtbr6rry2wpu - models.py: bafybeih4kchpjcc4nvfo5ycayaqatemqnl6rdne2sq27vodz3sy4ijech4 + models.py: bafybeicnecvc2jz6c6u7kadl4p6e2triu5gkhvvnavz2cnofw7wqakgiz4 test_tools/__init__.py: bafybeibayeahoo73eztt2chpwi45taj2uv3dxbpyn47ksqfjoepjyaoca4 - test_tools/abci_app.py: bafybeicnd4xvumelx2fgp46kxt62usoq3pp3zrcgmpsr6ufu56k5ozh5mm - test_tools/base.py: bafybeib2ynevixrujorskv36x3ywlstimjlltybmtwfrslmec3dtjykteq + test_tools/abci_app.py: bafybeigmrjzxfoc63xgecyngdecz4msvze4aw2iejcjewatjefjbvdlmce + test_tools/base.py: bafybeibef4lclyecne5qj4zaxnaxaqzwpxjaitqqmddgsiezduhb7pfxly test_tools/common.py: bafybeibxlx7es632kdoeivfrjahns3kknkxfmw4rj2dcxjwqm5j6vx25sq test_tools/integration.py: bafybeifqq3bx46hz2deph3usvrt7u45tpsapvocofd2zu3yh7rfl5nlmzq test_tools/rounds.py: bafybeie576yxtiramzt5czpt4hnv76gfetzio2t3k5kprhdhvbpfddbaem - tests/__init__.py: bafybeiebss5rdfh7tdbw2qi3tjpf6cjgwuonowsw6bimyosfie2ngxhhzy - tests/conftest.py: bafybeib2tebjwysgej4kpczd7tmxi2a2ikinzvoav25buogofujz47kj54 + tests/__init__.py: bafybeibrtwn3sbl7ynxjoiax64sh3wqtsjpcgemp5gbrtxpue7h5m3uamu + tests/conftest.py: bafybeiauvmnuetxooprdsy3vlys3pha6x2rfg7acr3xrdfffr7onlmnave tests/data/__init__.py: bafybeifmqjnrqgbau4tshhdtrosru7xyjky72ljlrf3ynrk76fxjcsgfpi tests/data/dummy_abci/__init__.py: bafybeiaoqyjlgez5gkvutl22ihebcjk3zskve5gdt5wbap5zkmhehoddca tests/data/dummy_abci/behaviours.py: bafybeibei4ngebbktuq6a2uvwhrulgkvn6uhaj5k3a75zihkxwnfarqh4m @@ -37,46 +37,46 @@ fingerprint: tests/data/dummy_abci/models.py: bafybeiear3i45wbaylrkbnm2fbtqorxx56glul36piuah7m7jb56f5rpoq tests/data/dummy_abci/payloads.py: bafybeiczldqiumb7prcusb7l5vb575vschwyseyigpupvteldfyz7h6fyi tests/data/dummy_abci/rounds.py: bafybeihhheznpcntg4z5cdd7dysnivo2g4x5biv7blriyiyoouqp6xf5aq - tests/test_abci_app_chain.py: bafybeif6mf6cs22q7ynsigaz2smi5wqivqz4gjcnjjiyujt6b2qwtba7py - tests/test_base.py: bafybeiek357ciorty2flxg2l6omccgl55yoi3vonrmp5tssl6nx6y4urja - tests/test_base_rounds.py: bafybeiatnef47roakdc6g6wvz3wxppb4wdwu2vqoumakkdnz5ehfgzfjea - tests/test_behaviours.py: bafybeihceyipgxwfcglyaefx3hi6hycji2vdymzi57xu7c5i7j2ghsw2za - tests/test_behaviours_utils.py: bafybeihlvphptgz3lx4y7n7j3aedhkay5alsqw2gmodjz2cqtxd5ylh7ca - tests/test_common.py: bafybeigruyqp6h4qim3nsijeg5mvoot2dei2yzm5zxpank22vjyyiaysue + tests/test_abci_app_chain.py: bafybeihqvjkcwkwxowhb3umtk52us4pd5f6nbppw4ycx76oljw4j3j7xpa + tests/test_base.py: bafybeifkja3qckaznt5qt2aexzu6deujpdt35r3m64qofdsdelbptijp2q + tests/test_base_rounds.py: bafybeiadkpwuhz6y5k5ffvoqvyi6nqetf5ov5bmodejge7yvscm6yqzpse + tests/test_behaviours.py: bafybeidcuzy4c3rp6ir7yftegafe4qd54j6qkqymbrb4ixqrld3eas3poe + tests/test_behaviours_utils.py: bafybeifzcuzqliog4gewaiu64rvgtjjg75fpqr2wm2oun7nqmk2mvbjxie + tests/test_common.py: bafybeiekicwjh3vu5kqppictya2bmqm3p5dcauj7cvsiunvhhultpzmyla tests/test_dialogues.py: bafybeigpfrslqaz2yullyehia5bsl7cmy2qqxtz627ig7rbrypw5xfzeum - tests/test_handlers.py: bafybeiho7ruvh6gilajz5ns6cljdrxis2tzualmgkksprwdpm7art4ambm + tests/test_handlers.py: bafybeih64lmsukci3oc5mwi636gntyx243xnbzwx64dwjxittch77qyqsu tests/test_io/__init__.py: bafybeid3sssvbbyju4snrdssxyafleuo57sqyuepl25btxcbuj3p5oonsm - tests/test_io/test_ipfs.py: bafybeihkazdsdooi3vuypf4nu5g6pqnp5xmxg2vjjv4hlwgfl4gsyzaape + tests/test_io/test_ipfs.py: bafybeidm6f6naq6y7ntoivrqon2bkwdvd2dqru467fxqvgonv5oq5huhra tests/test_io/test_load.py: bafybeidgnxt5rt67ackbcgi5vnlliedxakcnzgihogplolck7kp57pc6iy tests/test_io/test_store.py: bafybeid2zbdjtgbplenacudk6re7si7dloqs2u7faqt7vhapjipjuw35ku - tests/test_models.py: bafybeihuwrekqrn7eydexcxyj6po5vpbomgktjpvvzbd6drzriz4rgjxm4 + tests/test_models.py: bafybeicrbu6xtprfgwjs3msa3idilwqe3ymz5zx6xm326huhspzrdngrwi tests/test_tools/__init__.py: bafybeiew6gu4pgp2sjevq4dbnmv2ail5dph7vj4yi7h3eae4gzx7vj7cbq tests/test_tools/base.py: bafybeihi7ax53326dhin3riwwwk3bouqvsoeq26han4nspodzj6hrk3gia tests/test_tools/test_base.py: bafybeie2hox7v6sy677grl6awq57ouliohpwhmlvrypz5rqcz5gxsxn24y tests/test_tools/test_common.py: bafybeieauphpcqm5on7d2u2lc5lrf3esbhojp6sxlf7phrlmpqy5cfoitq tests/test_tools/test_integration.py: bafybeidxkvb2kizi7djrpuw446dqxo2v5s7j2dbdrdpfmnd2ggezaxbnkm - tests/test_tools/test_rounds.py: bafybeiccirhrajrvlhkwz4nmj4syw2jgxcrits5v4hfdxegepfd4idh6va - tests/test_utils.py: bafybeibs7zjpepzdetcy4ybksqxoul45hw372z4evkop3avx6qhrss3bba - utils.py: bafybeicckjeq5ubm25squfzevdwlwnios7enstmelc7tw4qpzcv2h7ysmq + tests/test_tools/test_rounds.py: bafybeibaoj4miysneipgukz7xufs47vpv5rds3ptgmu3yxlcl7gjss6ccm + tests/test_utils.py: bafybeift6igxoan2bnuexps7rrdl25jmlniqujw3odnir3cgjy4oukjjfq + utils.py: bafybeidbha3c3tcxo4lhucyx2x6yra4z2p2fp6sucqqzhxanbvgrraykbi fingerprint_ignore_patterns: [] connections: -- valory/abci:0.1.0:bafybeih2l6ssf5ebkvgbag3hx2pd22shytszqavveib2e2s6rv4va5khv4 -- valory/http_client:0.23.0:bafybeidykl4elwbcjkqn32wt5h4h7tlpeqovrcq3c5bcplt6nhpznhgczi -- valory/ipfs:0.1.0:bafybeihubpyw2t3bwncz3l7jt4gf5xvfydwmob463vvgf3ikkhlwxakm3m -- valory/ledger:0.19.0:bafybeicgfupeudtmvehbwziqfxiz6ztsxr5rxzvalzvsdsspzz73o5fzfi -- valory/p2p_libp2p_client:0.1.0:bafybeidwcobzb7ut3efegoedad7jfckvt2n6prcmd4g7xnkm6hp6aafrva +- valory/abci:0.1.0:bafybeih4lb2myvtypnfeji5jmgikmmazpgl3vyf5sy7oe66ji2zfjj6ily +- valory/http_client:0.23.0:bafybeiddrfvomrmgvh5yuv2coq7ci72wcdf663stayi3m5aawnj4srggce +- valory/ipfs:0.1.0:bafybeigjtca6b5wwiobl37es3wllzt6ai3qef5gqxzfy5fmmc65jkbnec4 +- valory/ledger:0.19.0:bafybeia47rr37ianvwsh77tjjpv3nwif5sywhhy2fbdshnz4a2icwln76a +- valory/p2p_libp2p_client:0.1.0:bafybeihge56dn3xep2dzomu7rtvbgo4uc2qqh7ljl3fubqdi2lq44gs5lq contracts: -- valory/service_registry:0.1.0:bafybeiatzikdgcjteti6xeid4bvofszuavxb4fnczx33lcsvlaui4wpwua +- valory/service_registry:0.1.0:bafybeieeuruq7dp4b6souetv5ce7wlm52pw7vyrxuhqa7kuy5m3rwwxks4 protocols: -- open_aea/signing:1.0.0:bafybeibqlfmikg5hk4phzak6gqzhpkt6akckx7xppbp53mvwt6r73h7tk4 -- valory/abci:0.1.0:bafybeig3dj5jhsowlvg3t73kgobf6xn4nka7rkttakdb2gwsg5bp7rt7q4 -- valory/contract_api:1.0.0:bafybeidv6wxpjyb2sdyibnmmum45et4zcla6tl63bnol6ztyoqvpl4spmy -- valory/http:1.0.0:bafybeifyoio7nlh5zzyn5yz7krkou56l22to3cwg7gw5v5o3vxwklibhty -- valory/ipfs:0.1.0:bafybeic72ncgqbzoz2guj4p4yjqulid7mv6yroeh65hxznloamoveeg7hq -- valory/ledger_api:1.0.0:bafybeibo4bdtcrxi2suyzldwoetjar6pqfzm6vt5xal22ravkkcvdmtksi -- valory/tendermint:0.1.0:bafybeicusvezoqlmyt6iqomcbwaz3xkhk2qf3d56q5zprmj3xdxfy64k54 +- open_aea/signing:1.0.0:bafybeie7xyems76v5b4wc2lmaidcujizpxfzjnnwdeokmhje53g7ym25ii +- valory/abci:0.1.0:bafybeihmzlmmb4pdo3zkhg6ehuyaa4lhw7bfpclln2o2z7v3o6fcep26iu +- valory/contract_api:1.0.0:bafybeialhbjvwiwcnqq3ysxcyemobcbie7xza66gaofcvla5njezkvhcka +- valory/http:1.0.0:bafybeiejoqgv7finfxo3rcvvovrlj5ccrbgxodjq43uo26ylpowsa3llfe +- valory/ipfs:0.1.0:bafybeiedxeismnx3k5ty4mvvhlqideixlhqmi5mtcki4lxqfa7uqh7p33u +- valory/ledger_api:1.0.0:bafybeige5agrztgzfevyglf7mb4o7pzfttmq4f6zi765y4g2zvftbyowru +- valory/tendermint:0.1.0:bafybeig6g6twajlwssfbfp5rlnu5mwzuu5kgak5cs4fich7rlkx6whesnu skills: -- valory/abstract_abci:0.1.0:bafybeifuclb6cikagtg2zn7dkjnnv3f7re2tfgzk6c4h3scgyzaaqeg55m +- valory/abstract_abci:0.1.0:bafybeial6drwstqlvuizgtouc4uqgxvutwryfu7yohondemd6bd7cw3jzm behaviours: main: args: {} @@ -145,17 +145,19 @@ dependencies: ipfshttpclient: version: ==0.8.0a2 open-aea-cli-ipfs: - version: ==1.32.0 + version: ==1.43.0.post2 open-aea-test-autonomy: - version: ==0.10.2 + version: ==0.13.9.post1 protobuf: - version: <=3.20.1,>=3.20 + version: <4.25.0,>=4.21.6 py-ecc: - version: ==5.2.0 + version: ==6.0.0 + pytest: + version: ==7.2.1 pytz: version: ==2022.2.1 requests: version: ==2.28.1 typing_extensions: - version: ==3.10.0.2 + version: '>=3.10.0.2' is_abstract: true diff --git a/packages/valory/skills/abstract_round_abci/test_tools/abci_app.py b/packages/valory/skills/abstract_round_abci/test_tools/abci_app.py index df6b35655b..10e1260961 100644 --- a/packages/valory/skills/abstract_round_abci/test_tools/abci_app.py +++ b/packages/valory/skills/abstract_round_abci/test_tools/abci_app.py @@ -30,6 +30,7 @@ AbstractRound, BaseSynchronizedData, BaseTxPayload, + DegenerateRound, ) @@ -77,6 +78,12 @@ class ConcreteBackgroundRound(_ConcreteRound): payload_class = BaseTxPayload +class ConcreteBackgroundSlashingRound(_ConcreteRound): + """Dummy instantiation of the AbstractRound class.""" + + payload_class = BaseTxPayload + + class ConcreteTerminationRoundA(_ConcreteRound): """Dummy instantiation of the AbstractRound class.""" @@ -95,13 +102,29 @@ class ConcreteTerminationRoundC(_ConcreteRound): payload_class = BaseTxPayload +class ConcreteSlashingRoundA(_ConcreteRound): + """Dummy instantiation of the AbstractRound class.""" + + payload_class = BaseTxPayload + + +class ConcreteSlashingRoundB(_ConcreteRound): + """Dummy instantiation of the AbstractRound class.""" + + payload_class = BaseTxPayload + + class ConcreteEvents(Enum): """Defines dummy events to be used for testing purposes.""" TERMINATE = "terminate" + PENDING_OFFENCE = "pending_offence" + SLASH_START = "slash_start" + SLASH_END = "slash_end" A = "a" B = "b" C = "c" + D = "c" TIMEOUT = "timeout" def __str__(self) -> str: @@ -109,6 +132,49 @@ def __str__(self) -> str: return self.value +class TerminationAppTest(AbciApp[ConcreteEvents]): + """A dummy Termination abci for testing purposes.""" + + initial_round_cls: Type[AbstractRound] = ConcreteBackgroundRound + transition_function: Dict[ + Type[AbstractRound], Dict[ConcreteEvents, Type[AbstractRound]] + ] = { + ConcreteBackgroundRound: { + ConcreteEvents.TERMINATE: ConcreteTerminationRoundA, + }, + ConcreteTerminationRoundA: { + ConcreteEvents.A: ConcreteTerminationRoundA, + ConcreteEvents.B: ConcreteTerminationRoundB, + ConcreteEvents.C: ConcreteTerminationRoundC, + }, + ConcreteTerminationRoundB: { + ConcreteEvents.B: ConcreteTerminationRoundB, + ConcreteEvents.TIMEOUT: ConcreteTerminationRoundA, + }, + ConcreteTerminationRoundC: { + ConcreteEvents.C: ConcreteTerminationRoundA, + ConcreteEvents.TIMEOUT: ConcreteTerminationRoundC, + }, + } + + +class SlashingAppTest(AbciApp[ConcreteEvents]): + """A dummy Slashing abci for testing purposes.""" + + initial_round_cls: Type[AbstractRound] = ConcreteBackgroundSlashingRound + transition_function: Dict[ + Type[AbstractRound], Dict[ConcreteEvents, Type[AbstractRound]] + ] = { + ConcreteBackgroundSlashingRound: { + ConcreteEvents.SLASH_START: ConcreteSlashingRoundA, + }, + ConcreteSlashingRoundA: {ConcreteEvents.D: ConcreteSlashingRoundB}, + ConcreteSlashingRoundB: { + ConcreteEvents.SLASH_END: DegenerateRound, + }, + } + + class AbciAppTest(AbciApp[ConcreteEvents]): """A dummy AbciApp for testing purposes.""" @@ -132,28 +198,6 @@ class AbciAppTest(AbciApp[ConcreteEvents]): ConcreteEvents.TIMEOUT: ConcreteRoundC, }, } - background_round_cls = ConcreteBackgroundRound - termination_transition_function: Dict[ - Type[AbstractRound], Dict[ConcreteEvents, Type[AbstractRound]] - ] = { - ConcreteBackgroundRound: { - ConcreteEvents.TERMINATE: ConcreteTerminationRoundA, - }, - ConcreteTerminationRoundA: { - ConcreteEvents.A: ConcreteTerminationRoundA, - ConcreteEvents.B: ConcreteTerminationRoundB, - ConcreteEvents.C: ConcreteTerminationRoundC, - }, - ConcreteTerminationRoundB: { - ConcreteEvents.B: ConcreteTerminationRoundB, - ConcreteEvents.TIMEOUT: ConcreteTerminationRoundA, - }, - ConcreteTerminationRoundC: { - ConcreteEvents.C: ConcreteTerminationRoundA, - ConcreteEvents.TIMEOUT: ConcreteTerminationRoundC, - }, - } - termination_event = ConcreteEvents.TERMINATE event_to_timeout: Dict[ConcreteEvents, float] = { ConcreteEvents.TIMEOUT: TIMEOUT, } diff --git a/packages/valory/skills/abstract_round_abci/test_tools/base.py b/packages/valory/skills/abstract_round_abci/test_tools/base.py index c68b6a94a3..30640e9413 100644 --- a/packages/valory/skills/abstract_round_abci/test_tools/base.py +++ b/packages/valory/skills/abstract_round_abci/test_tools/base.py @@ -396,7 +396,7 @@ def end_round(self, done_event: Enum) -> None: abci_app._last_round = old_round abci_app._current_round = abci_app.transition_function[ current_behaviour.matching_round - ][done_event](abci_app.synchronized_data) + ][done_event](abci_app.synchronized_data, context=MagicMock()) abci_app._previous_rounds.append(old_round) abci_app._current_round_height += 1 self.behaviour._process_current_round() @@ -435,6 +435,7 @@ class params: round_timeout_seconds: float = 1.0 _skill: MagicMock = MagicMock() + logger: MagicMock = MagicMock() skill_id = "dummy_skill_id" @property diff --git a/packages/valory/skills/abstract_round_abci/tests/__init__.py b/packages/valory/skills/abstract_round_abci/tests/__init__.py index 1ede0e87d7..5ea3cb8b48 100644 --- a/packages/valory/skills/abstract_round_abci/tests/__init__.py +++ b/packages/valory/skills/abstract_round_abci/tests/__init__.py @@ -18,3 +18,10 @@ # ------------------------------------------------------------------------------ """Tests for valory/abstract_round_abci skill.""" + +from hypothesis import settings # pragma: nocover + + +CI = "CI" # pragma: nocover + +settings.register_profile(CI, deadline=5000) # pragma: nocover diff --git a/packages/valory/skills/abstract_round_abci/tests/conftest.py b/packages/valory/skills/abstract_round_abci/tests/conftest.py index 7d9cb1faf3..5dde4f1b0b 100644 --- a/packages/valory/skills/abstract_round_abci/tests/conftest.py +++ b/packages/valory/skills/abstract_round_abci/tests/conftest.py @@ -108,4 +108,9 @@ def hypothesis_cleanup() -> Generator: "setup": {}, "genesis_config": irrelevant_genesis_config, "use_termination": False, + "use_slashing": False, + "slash_cooldown_hours": 3, + "slash_threshold_amount": 10_000_000_000_000_000, + "light_slash_unit_amount": 5_000_000_000_000_000, + "serious_slash_unit_amount": 8_000_000_000_000_000, } diff --git a/packages/valory/skills/abstract_round_abci/tests/data/dummy_abci/skill.yaml b/packages/valory/skills/abstract_round_abci/tests/data/dummy_abci/skill.yaml index c82fa8fec7..4ac35e9e05 100644 --- a/packages/valory/skills/abstract_round_abci/tests/data/dummy_abci/skill.yaml +++ b/packages/valory/skills/abstract_round_abci/tests/data/dummy_abci/skill.yaml @@ -115,6 +115,11 @@ models: share_tm_config_on_startup: false tendermint_p2p_url: localhost:26656 use_termination: false + use_slashing: false + slash_cooldown_hours: 3 + slash_threshold_amount: 10_000_000_000_000_000 + light_slash_unit_amount: 5_000_000_000_000_000 + serious_slash_unit_amount: 8_000_000_000_000_000 class_name: Params randomness_api: args: diff --git a/packages/valory/skills/abstract_round_abci/tests/test_abci_app_chain.py b/packages/valory/skills/abstract_round_abci/tests/test_abci_app_chain.py index 280cccf61a..4a95580cf6 100644 --- a/packages/valory/skills/abstract_round_abci/tests/test_abci_app_chain.py +++ b/packages/valory/skills/abstract_round_abci/tests/test_abci_app_chain.py @@ -412,7 +412,7 @@ def end_block(self) -> None: (self.app2_class, sync_data_cls_app2), ): synchronized_data = sync_data_cls(db=AbciAppDB(setup_data={})) - abci_app = abci_app_cls(synchronized_data, logging.getLogger()) + abci_app = abci_app_cls(synchronized_data, logging.getLogger(), MagicMock()) for r in abci_app_cls.get_all_rounds(): r.synchronized_data_class = sync_data_cls @@ -420,7 +420,7 @@ def end_block(self) -> None: (self.app1_class, self.app2_class), abci_app_transition_mapping ) synchronized_data = sync_data_cls_app2(db=AbciAppDB(setup_data={})) - abci_app = abci_app_cls(synchronized_data, logging.getLogger()) + abci_app = abci_app_cls(synchronized_data, logging.getLogger(), MagicMock()) assert abci_app.initial_round_cls == self.round_1a assert isinstance(abci_app.synchronized_data, sync_data_cls_app1) diff --git a/packages/valory/skills/abstract_round_abci/tests/test_base.py b/packages/valory/skills/abstract_round_abci/tests/test_base.py index ffcbf836d7..5ee32ebecc 100644 --- a/packages/valory/skills/abstract_round_abci/tests/test_base.py +++ b/packages/valory/skills/abstract_round_abci/tests/test_base.py @@ -26,6 +26,8 @@ import re import shutil from abc import ABC +from calendar import timegm +from collections import deque from contextlib import suppress from copy import copy, deepcopy from dataclasses import dataclass @@ -33,6 +35,8 @@ from time import sleep from typing import ( Any, + Callable, + Deque, Dict, FrozenSet, Generator, @@ -50,20 +54,37 @@ from _pytest.logging import LogCaptureFixture from aea.exceptions import AEAEnforceError from aea_ledger_ethereum import EthereumCrypto -from hypothesis import given, settings +from hypothesis import HealthCheck, given, settings from hypothesis.strategies import ( + DrawFn, + binary, booleans, + builds, + composite, + data, datetimes, dictionaries, floats, integers, + just, + lists, none, one_of, + sampled_from, text, ) import packages.valory.skills.abstract_round_abci.base as abci_base from packages.valory.connections.abci.connection import MAX_READ_IN_BYTES +from packages.valory.protocols.abci.custom_types import ( + Evidence, + EvidenceType, + Evidences, + LastCommitInfo, + Timestamp, + Validator, + VoteInfo, +) from packages.valory.skills.abstract_round_abci.base import ( ABCIAppException, ABCIAppInternalError, @@ -74,6 +95,7 @@ AbstractRoundInternalError, AddBlockError, AppState, + AvailabilityWindow, BaseSynchronizedData, BaseTxPayload, Block, @@ -82,8 +104,13 @@ CollectionRound, EventType, LateArrivingTransaction, + OffenceStatus, + OffenseStatusDecoder, + OffenseStatusEncoder, + OffenseType, RoundSequence, SignatureNotValidError, + SlashingNotConfiguredError, Timeouts, Transaction, TransactionTypeNotRecognizedError, @@ -91,17 +118,27 @@ _MetaAbstractRound, _MetaPayload, get_name, + light_offences, + serious_offences, ) from packages.valory.skills.abstract_round_abci.test_tools.abci_app import ( AbciAppTest, ConcreteBackgroundRound, + ConcreteBackgroundSlashingRound, ConcreteEvents, ConcreteRoundA, ConcreteRoundB, ConcreteRoundC, + ConcreteSlashingRoundA, ConcreteTerminationRoundA, ConcreteTerminationRoundB, ConcreteTerminationRoundC, + SlashingAppTest, + TerminationAppTest, +) +from packages.valory.skills.abstract_round_abci.test_tools.rounds import ( + BaseRoundTestClass, + get_participants, ) from packages.valory.skills.abstract_round_abci.tests.conftest import profile_name @@ -199,7 +236,9 @@ def test_base_tx_payload() -> None: assert type(hash(payload)) == int -def test_meta_round_abstract_round_when_instance_not_subclass_of_abstract_round() -> None: +def test_meta_round_abstract_round_when_instance_not_subclass_of_abstract_round() -> ( + None +): """Test instantiation of meta class when instance not a subclass of abstract round.""" class MyAbstractRound(metaclass=_MetaAbstractRound): @@ -874,39 +913,64 @@ def test_cleanup( """Test cleanup db.""" db = AbciAppDB({}) db._cross_period_persisted_keys = frozenset() - for _, data in existing_data.items(): - db._create_from_keys(**data) + for _, _data in existing_data.items(): + db._create_from_keys(**_data) db.cleanup(cleanup_history_depth, cleanup_history_depth_current) assert db._data == expected def test_serialize(self) -> None: """Test `serialize` method.""" - assert self.db.serialize() == '{"0": {"participants": [["a", "b"]]}}' + assert ( + self.db.serialize() + == '{"db_data": {"0": {"participants": [["a", "b"]]}}, "slashing_config": ""}' + ) - @pytest.mark.parametrize("data", ({0: {"test": [0]}},)) - def test_sync(self, data: Dict[int, Dict[str, List[Any]]]) -> None: + @pytest.mark.parametrize( + "_data", + ({"db_data": {0: {"test": [0]}}, "slashing_config": "serialized_config"},), + ) + def test_sync(self, _data: Dict[str, Dict[int, Dict[str, List[Any]]]]) -> None: """Test `sync` method.""" try: - serialized_data = json.dumps(data) + serialized_data = json.dumps(_data) except TypeError as exc: raise AssertionError( "Incorrectly parametrized test. Data must be json serializable." ) from exc self.db.sync(serialized_data) - assert self.db._data == data + assert self.db._data == _data["db_data"] + assert self.db.slashing_config == _data["slashing_config"] @pytest.mark.parametrize( "serialized_data, match", ( (b"", "Could not decode data using "), ( - json.dumps({"invalid_index": {}}), + json.dumps({"both_mandatory_keys_missing": {}}), + "internal error: Mandatory keys `db_data`, `slashing_config` are missing from the deserialized data: " + "{'both_mandatory_keys_missing': {}}\nThe following serialized data were given: " + '{"both_mandatory_keys_missing": {}}', + ), + ( + json.dumps({"db_data": {}}), + "internal error: Mandatory keys `db_data`, `slashing_config` are missing from the deserialized data: " + "{'db_data': {}}\nThe following serialized data were given: {\"db_data\": {}}", + ), + ( + json.dumps({"slashing_config": {}}), + "internal error: Mandatory keys `db_data`, `slashing_config` are missing from the deserialized data: " + "{'slashing_config': {}}\nThe following serialized data were given: {\"slashing_config\": {}}", + ), + ( + json.dumps( + {"db_data": {"invalid_index": {}}, "slashing_config": "anything"} + ), "An invalid index was found while trying to sync the db using data: ", ), ( - json.dumps("invalid"), + json.dumps({"db_data": "invalid", "slashing_config": "anything"}), "Could not decode db data with an invalid format: ", ), ), @@ -921,7 +985,10 @@ def test_sync_incorrect_data(self, serialized_data: Any, match: str) -> None: def test_hash(self) -> None: """Test `hash` method.""" - expected_hash = b"\x89j\xd8\xf7\x9b\x98>\x97b|\xbeI~y\x8b\x9a\xba\x92\xd4I\x05 \xe8\xc9\xcaQ\x80\xbf{:\xef\xc2" + expected_hash = ( + b"\xd0^\xb0\x85\xf1\xf5\xd2\xe8\xe8\x85\xda\x1a\x99k" + b"\x1c\xde\xfa1\x8a\x87\xcc\xd7q?\xdf\xbbofz\xfb\x7fI" + ) assert self.db.hash() == expected_hash @@ -935,6 +1002,16 @@ def setup(self) -> None: db=AbciAppDB(setup_data=dict(participants=[self.participants])) ) + @given(text()) + def test_slashing_config(self, slashing_config: str) -> None: + """Test the `slashing_config` property.""" + self.base_synchronized_data.slashing_config = slashing_config + assert ( + self.base_synchronized_data.slashing_config + == self.base_synchronized_data.db.slashing_config + == slashing_config + ) + def test_participants_getter_positive(self) -> None: """Test 'participants' property getter.""" assert frozenset(self.participants) == self.base_synchronized_data.participants @@ -1162,7 +1239,7 @@ def setup(self) -> None: ) ) ) - self.round = ConcreteRoundA(self.base_synchronized_data) + self.round = ConcreteRoundA(self.base_synchronized_data, MagicMock()) def test_auto_round_id(self) -> None: """Test that the 'auto_round_id()' method works as expected.""" @@ -1173,7 +1250,7 @@ def test_must_not_set_round_id(self) -> None: """Test that the 'round_id' must be set in concrete classes.""" # no exception as round id is auto-assigned - my_concrete_round = DummyConcreteRound(MagicMock()) + my_concrete_round = DummyConcreteRound(MagicMock(), MagicMock()) assert my_concrete_round.round_id == "dummy_concrete_round" def test_must_set_payload_class_type(self) -> None: @@ -1184,7 +1261,6 @@ def test_must_set_payload_class_type(self) -> None: ): class MyConcreteRound(AbstractRound): - synchronized_data_class = MagicMock() payload_attribute = MagicMock() # here payload_class is missing @@ -1198,7 +1274,7 @@ class MyConcreteRound(DummyConcreteRound): payload_class = BaseTxPayload with pytest.raises(LateArrivingTransaction): - MyConcreteRound(MagicMock(), BaseTxPayload).check_payload_type( + MyConcreteRound(MagicMock(), MagicMock(), BaseTxPayload).check_payload_type( MagicMock(payload=BaseTxPayload("dummy")) ) @@ -1209,7 +1285,7 @@ def test_check_payload_type(self) -> None: TransactionTypeNotRecognizedError, match="current round does not allow transactions", ): - DummyConcreteRound(MagicMock()).check_payload_type(MagicMock()) + DummyConcreteRound(MagicMock(), MagicMock()).check_payload_type(MagicMock()) def test_synchronized_data_getter(self) -> None: """Test 'synchronized_data' property getter.""" @@ -1268,13 +1344,15 @@ def test_check_majority_possible_raises_error_when_nb_participants_is_0( ABCIAppInternalError, match="nb_participants not consistent with votes_by_participants", ): - DummyConcreteRound(self.base_synchronized_data).check_majority_possible( - {}, 0 - ) + DummyConcreteRound( + self.base_synchronized_data, MagicMock() + ).check_majority_possible({}, 0) def test_check_majority_possible_passes_when_vote_set_is_empty(self) -> None: """Check that 'check_majority_possible' passes when the set of votes is empty.""" - DummyConcreteRound(self.base_synchronized_data).check_majority_possible({}, 1) + DummyConcreteRound( + self.base_synchronized_data, MagicMock() + ).check_majority_possible({}, 1) def test_check_majority_possible_passes_when_vote_set_nonempty_and_check_passes( self, @@ -1286,9 +1364,9 @@ def test_check_majority_possible_passes_when_vote_set_nonempty_and_check_passes( - the threshold is 2 - the other voter can vote for the same item of the first voter """ - DummyConcreteRound(self.base_synchronized_data).check_majority_possible( - {"alice": DummyPayload("alice", True)}, 2 - ) + DummyConcreteRound( + self.base_synchronized_data, MagicMock() + ).check_majority_possible({"alice": DummyPayload("alice", True)}, 2) def test_check_majority_possible_passes_when_payload_attributes_majority_match( self, @@ -1300,7 +1378,9 @@ def test_check_majority_possible_passes_when_payload_attributes_majority_match( - the threshold is 3 (participants are 4) - 3 voters have the same attribute value in their payload """ - DummyConcreteRound(self.base_synchronized_data).check_majority_possible( + DummyConcreteRound( + self.base_synchronized_data, MagicMock() + ).check_majority_possible( { "voter_1": DummyPayload("voter_1", 0), "voter_2": DummyPayload("voter_2", 0), @@ -1323,7 +1403,9 @@ def test_check_majority_possible_passes_when_vote_set_nonempty_and_check_doesnt_ ABCIAppException, match="cannot reach quorum=2, number of remaining votes=0, number of most voted item's votes=1", ): - DummyConcreteRound(self.base_synchronized_data).check_majority_possible( + DummyConcreteRound( + self.base_synchronized_data, MagicMock() + ).check_majority_possible( { "alice": DummyPayload("alice", False), "bob": DummyPayload("bob", True), @@ -1333,13 +1415,15 @@ def test_check_majority_possible_passes_when_vote_set_nonempty_and_check_doesnt_ def test_is_majority_possible_positive_case(self) -> None: """Test 'is_majority_possible', positive case.""" - assert DummyConcreteRound(self.base_synchronized_data).is_majority_possible( - {"alice": DummyPayload("alice", False)}, 2 - ) + assert DummyConcreteRound( + self.base_synchronized_data, MagicMock() + ).is_majority_possible({"alice": DummyPayload("alice", False)}, 2) def test_is_majority_possible_negative_case(self) -> None: """Test 'is_majority_possible', negative case.""" - assert not DummyConcreteRound(self.base_synchronized_data).is_majority_possible( + assert not DummyConcreteRound( + self.base_synchronized_data, MagicMock() + ).is_majority_possible( { "alice": DummyPayload("alice", False), "bob": DummyPayload("bob", True), @@ -1353,7 +1437,8 @@ def test_check_majority_possible_raises_error_when_new_voter_already_voted( """Test 'check_majority_possible_with_new_vote' raises when new voter already voted.""" with pytest.raises(ABCIAppInternalError, match="voter has already voted"): DummyConcreteRound( - self.base_synchronized_data + self.base_synchronized_data, + MagicMock(), ).check_majority_possible_with_new_voter( {"alice": DummyPayload("alice", False)}, "alice", @@ -1370,7 +1455,8 @@ def test_check_majority_possible_raises_error_when_nb_participants_inconsistent( match="nb_participants not consistent with votes_by_participants", ): DummyConcreteRound( - self.base_synchronized_data + self.base_synchronized_data, + MagicMock(), ).check_majority_possible_with_new_voter( {"alice": DummyPayload("alice", True)}, "bob", @@ -1389,7 +1475,8 @@ def test_check_majority_possible_when_check_passes( - the new voter votes for the same item already voted by voter 1. """ DummyConcreteRound( - self.base_synchronized_data + self.base_synchronized_data, + MagicMock(), ).check_majority_possible_with_new_voter( {"alice": DummyPayload("alice", True)}, "bob", DummyPayload("bob", True), 2 ) @@ -1512,12 +1599,31 @@ def test_pop_timeout(self) -> None: assert self.timeouts.size == 1 +STUB_TERMINATION_CONFIG = abci_base.BackgroundAppConfig( + round_cls=ConcreteBackgroundRound, + start_event=ConcreteEvents.TERMINATE, + abci_app=TerminationAppTest, +) + +STUB_SLASH_CONFIG = abci_base.BackgroundAppConfig( + round_cls=ConcreteBackgroundSlashingRound, + start_event=ConcreteEvents.SLASH_START, + end_event=ConcreteEvents.SLASH_END, + abci_app=SlashingAppTest, +) + + class TestAbciApp: """Test the 'AbciApp' class.""" def setup(self) -> None: """Set up the test.""" - self.abci_app = AbciAppTest(MagicMock(), MagicMock()) + self.abci_app = AbciAppTest(MagicMock(), MagicMock(), MagicMock()) + self.abci_app.add_background_app(STUB_TERMINATION_CONFIG) + + def teardown(self) -> None: + """Teardown the test.""" + self.abci_app.background_apps.clear() @pytest.mark.parametrize("flag", (True, False)) def test_is_abstract(self, flag: bool) -> None: @@ -1565,15 +1671,36 @@ def test_last_timestamp_positive(self) -> None: def test_process_event(self) -> None: """Test the 'process_event' method, positive case, with timeout events.""" + self.abci_app.add_background_app(STUB_SLASH_CONFIG) self.abci_app.setup() self.abci_app._last_timestamp = MagicMock() + assert self.abci_app._transition_backup.transition_function is None assert isinstance(self.abci_app.current_round, ConcreteRoundA) self.abci_app.process_event(ConcreteEvents.B) assert isinstance(self.abci_app.current_round, ConcreteRoundB) self.abci_app.process_event(ConcreteEvents.TIMEOUT) assert isinstance(self.abci_app.current_round, ConcreteRoundA) - self.abci_app.process_event(self.abci_app.termination_event) + self.abci_app.process_event(ConcreteEvents.TERMINATE) + assert isinstance(self.abci_app.current_round, ConcreteTerminationRoundA) + expected_backup = deepcopy(self.abci_app.transition_function) + assert ( + self.abci_app._transition_backup.transition_function + == AbciAppTest.transition_function + ) + self.abci_app.process_event(ConcreteEvents.SLASH_START) + assert isinstance(self.abci_app.current_round, ConcreteSlashingRoundA) + assert ( + self.abci_app._transition_backup.transition_function + == expected_backup + == TerminationAppTest.transition_function + ) + assert self.abci_app.transition_function == SlashingAppTest.transition_function + self.abci_app.process_event(ConcreteEvents.SLASH_END) + # should return back to the round that was running before the slashing started assert isinstance(self.abci_app.current_round, ConcreteTerminationRoundA) + assert self.abci_app.transition_function == expected_backup + assert self.abci_app._transition_backup.transition_function is None + assert self.abci_app._transition_backup.round is None def test_process_event_negative_case(self) -> None: """Test the 'process_event' method, negative case.""" @@ -1627,81 +1754,76 @@ def test_get_all_events(self) -> None: ConcreteEvents.TIMEOUT, } == self.abci_app.get_all_events() - def test_get_all_rounds_classes(self) -> None: + @pytest.mark.parametrize("include_background_rounds", (True, False)) + def test_get_all_rounds_classes( + self, + include_background_rounds: bool, + ) -> None: """Test the get all rounds getter.""" expected_rounds = {ConcreteRoundA, ConcreteRoundB, ConcreteRoundC} - assert expected_rounds == self.abci_app.get_all_round_classes() - def test_get_all_rounds_classes_including_termination(self) -> None: - """Test the get all rounds getter when the termination rounds should be included.""" - include_termination_rounds = True + if include_background_rounds: + expected_rounds.update( + { + ConcreteBackgroundRound, + ConcreteTerminationRoundA, + ConcreteTerminationRoundB, + ConcreteTerminationRoundC, + } + ) + + actual_rounds = self.abci_app.get_all_round_classes( + {ConcreteBackgroundRound}, include_background_rounds + ) + + assert actual_rounds == expected_rounds + + def test_get_all_rounds_classes_bg_ever_running( + self, + ) -> None: + """Test the get all rounds when the background round is of an ever running type.""" + # we clear the pre-existing bg apps and add an ever running + self.abci_app.background_apps.clear() + self.abci_app.add_background_app( + abci_base.BackgroundAppConfig(ConcreteBackgroundRound) + ) + include_background_rounds = True expected_rounds = { ConcreteRoundA, ConcreteRoundB, ConcreteRoundC, - ConcreteBackgroundRound, - ConcreteTerminationRoundA, - ConcreteTerminationRoundB, - ConcreteTerminationRoundC, } assert expected_rounds == self.abci_app.get_all_round_classes( - include_termination_rounds + {ConcreteBackgroundRound}, include_background_rounds ) - def test_get_all_rounds_classes_including_termination_no_termination_rounds( - self, - ) -> None: - """Test the get all rounds when the termination rounds are not set.""" - # we set termination_transition_function to its default value (None) - with mock.patch.object( - AbciAppTest, "termination_transition_function", return_value=None - ): - include_termination_rounds = True - expected_rounds = { - ConcreteRoundA, - ConcreteRoundB, - ConcreteRoundC, - } - assert expected_rounds == self.abci_app.get_all_round_classes( - include_termination_rounds - ) - - def test_add_termination(self) -> None: - """Tests the `add_termination` method.""" + def test_add_background_app(self) -> None: + """Tests the add method for the background apps.""" + # remove the terminating bg round added in `setup()` and the pending offences bg app added in the metaclass + self.abci_app.background_apps.clear() class EmptyAbciApp(AbciAppTest): - """An AbciApp without termination attrs set.""" + """An AbciApp without background apps' attributes set.""" cross_period_persisted_keys = frozenset({"1", "2"}) - class TerminationAbciApp(AbciAppTest): - """A moch termination AbciApp.""" + class BackgroundAbciApp(AbciAppTest): + """A mock background AbciApp.""" cross_period_persisted_keys = frozenset({"2", "3"}) - EmptyAbciApp.add_termination( - TerminationAbciApp.background_round_cls, - TerminationAbciApp.termination_event, - TerminationAbciApp, + assert len(EmptyAbciApp.background_apps) == 0 + assert EmptyAbciApp.cross_period_persisted_keys == {"1", "2"} + # add the background app + bg_app_config = abci_base.BackgroundAppConfig( + round_cls=ConcreteBackgroundRound, + start_event=ConcreteEvents.TERMINATE, + abci_app=BackgroundAbciApp, ) - - assert EmptyAbciApp.background_round_cls is not None - assert EmptyAbciApp.termination_transition_function is not None - assert EmptyAbciApp.termination_event is not None + EmptyAbciApp.add_background_app(bg_app_config) + assert len(EmptyAbciApp.background_apps) == 1 assert EmptyAbciApp.cross_period_persisted_keys == {"1", "2", "3"} - def test_background_round(self) -> None: - """Test the background_round property.""" - self.abci_app.setup() - assert self.abci_app.background_round is not None - - def test_background_round_negative(self) -> None: - """Test the background_round property when _background_round is not set.""" - # notice that we don't call `self.abci_app.setup()` here - # which is why this test works - with pytest.raises(ValueError, match="background_round not set!"): - self.abci_app.background_round - def test_cleanup(self) -> None: """Test the cleanup method.""" self.abci_app.setup() @@ -1713,7 +1835,7 @@ def test_cleanup(self) -> None: dummy_synchronized_data = BaseSynchronizedData( db=AbciAppDB(setup_data=dict(participants=[max_participants])) ) - dummy_round = ConcreteRoundA(dummy_synchronized_data) + dummy_round = ConcreteRoundA(dummy_synchronized_data, MagicMock()) # Add dummy data self.abci_app._previous_rounds = [dummy_round] * start_history_depth @@ -1764,12 +1886,12 @@ def test_cleanup(self) -> None: "transaction", [mock.MagicMock(payload=DUMMY_CONCRETE_BACKGROUND_PAYLOAD)], ) - def test_check_transaction_for_background_round( + def test_check_transaction_for_termination_round( self, check_transaction_mock: mock.Mock, transaction: Transaction, ) -> None: - """Tests process_transaction when it's a transaction meant for the background app.""" + """Tests process_transaction when it's a transaction meant for the termination app.""" self.abci_app.setup() self.abci_app.check_transaction(transaction) check_transaction_mock.assert_called_with(transaction) @@ -1779,26 +1901,548 @@ def test_check_transaction_for_background_round( "transaction", [mock.MagicMock(payload=DUMMY_CONCRETE_BACKGROUND_PAYLOAD)], ) - def test_process_transaction_for_background_round( + def test_process_transaction_for_termination_round( self, process_transaction_mock: mock.Mock, transaction: Transaction, ) -> None: - """Tests process_transaction when it's a transaction meant for the background app.""" + """Tests process_transaction when it's a transaction meant for the termination app.""" self.abci_app.setup() self.abci_app.process_transaction(transaction) process_transaction_mock.assert_called_with(transaction) +class TestOffenceTypeFns: + """Test `OffenceType`-related functions.""" + + @staticmethod + def test_light_offences() -> None: + """Test `light_offences` function.""" + assert list(light_offences()) == [ + OffenseType.VALIDATOR_DOWNTIME, + OffenseType.INVALID_PAYLOAD, + OffenseType.BLACKLISTED, + OffenseType.SUSPECTED, + ] + + @staticmethod + def test_serious_offences() -> None: + """Test `serious_offences` function.""" + assert list(serious_offences()) == [ + OffenseType.UNKNOWN, + OffenseType.DOUBLE_SIGNING, + OffenseType.LIGHT_CLIENT_ATTACK, + ] + + +@composite +def availability_window_data(draw: DrawFn) -> Dict[str, int]: + """A strategy for building valid availability window data.""" + max_length = draw(integers(min_value=1, max_value=12_000)) + array = draw(integers(min_value=0, max_value=(2**max_length) - 1)) + num_positive = draw(integers(min_value=0, max_value=1_000_000)) + num_negative = draw(integers(min_value=0, max_value=1_000_000)) + + return { + "max_length": max_length, + "array": array, + "num_positive": num_positive, + "num_negative": num_negative, + } + + +class TestAvailabilityWindow: + """Test `AvailabilityWindow`.""" + + @staticmethod + @given(integers(min_value=1, max_value=100)) + def test_not_equal(max_length: int) -> None: + """Test the `add` method.""" + availability_window_1 = AvailabilityWindow(max_length) + availability_window_2 = AvailabilityWindow(max_length) + assert availability_window_1 == availability_window_2 + availability_window_2.add(False) + assert availability_window_1 != availability_window_2 + # test with a different type + assert availability_window_1 != MagicMock() + + @staticmethod + @given(integers(min_value=0, max_value=100), data()) + def test_add(max_length: int, hypothesis_data: Any) -> None: + """Test the `add` method.""" + if max_length < 1: + with pytest.raises( + ValueError, + match=f"An `AvailabilityWindow` with a `max_length` {max_length} < 1 is not valid.", + ): + AvailabilityWindow(max_length) + return + + availability_window = AvailabilityWindow(max_length) + + expected_positives = expected_negatives = 0 + for i in range(max_length): + value = hypothesis_data.draw(booleans()) + availability_window.add(value) + items_in = i + 1 + assert len(availability_window._window) == items_in + assert availability_window._window[-1] is value + expected_positives += 1 if value else 0 + assert availability_window._num_positive == expected_positives + expected_negatives = items_in - expected_positives + assert availability_window._num_negative == expected_negatives + + # max length is reached and window starts cycling + assert len(availability_window._window) == max_length + for _ in range(10): + value = hypothesis_data.draw(booleans()) + expected_popped_value = ( + None if max_length == 0 else availability_window._window[0] + ) + availability_window.add(value) + assert len(availability_window._window) == max_length + if expected_popped_value is not None: + expected_positives -= bool(expected_popped_value) + expected_negatives -= bool(not expected_popped_value) + expected_positives += bool(value) + expected_negatives += bool(not value) + assert availability_window._num_positive == expected_positives + assert availability_window._num_negative == expected_negatives + + @staticmethod + @given( + max_length=integers(min_value=1, max_value=30_000), + num_positive=integers(min_value=0), + num_negative=integers(min_value=0), + ) + @pytest.mark.parametrize( + "window, expected_serialization", + ( + (deque(()), 0), + (deque((False, False, False)), 0), + (deque((True, False, True)), 5), + (deque((True for _ in range(3))), 7), + ( + deque((True for _ in range(1000))), + int( + "10715086071862673209484250490600018105614048117055336074437503883703510511249361224931983788156958" + "58127594672917553146825187145285692314043598457757469857480393456777482423098542107460506237114187" + "79541821530464749835819412673987675591655439460770629145711964776865421676604298316526243868372056" + "68069375" + ), + ), + ), + ) + def test_to_dict( + max_length: int, + num_positive: int, + num_negative: int, + window: Deque, + expected_serialization: int, + ) -> None: + """Test `to_dict` method.""" + availability_window = AvailabilityWindow(max_length) + availability_window._num_positive = num_positive + availability_window._num_negative = num_negative + availability_window._window = window + assert availability_window.to_dict() == { + "max_length": max_length, + "array": expected_serialization, + "num_positive": num_positive, + "num_negative": num_negative, + } + + @staticmethod + @pytest.mark.parametrize( + "data_, key, validator, expected_error", + ( + ({"a": 1, "b": 2, "c": 3}, "a", lambda x: x > 0, None), + ( + {"a": 1, "b": 2, "c": 3}, + "d", + lambda x: x > 0, + r"Missing required key: d\.", + ), + ( + {"a": "1", "b": 2, "c": 3}, + "a", + lambda x: x > 0, + r"a must be of type int\.", + ), + ( + {"a": -1, "b": 2, "c": 3}, + "a", + lambda x: x > 0, + r"a has invalid value -1\.", + ), + ), + ) + def test_validate_key( + data_: dict, key: str, validator: Callable, expected_error: Optional[str] + ) -> None: + """Test the `_validate_key` method.""" + if expected_error: + with pytest.raises(ValueError, match=expected_error): + AvailabilityWindow._validate_key(data_, key, validator) + else: + AvailabilityWindow._validate_key(data_, key, validator) + + @staticmethod + @pytest.mark.parametrize( + "data_, error_regex", + ( + ("not a dict", r"Expected dict, got"), + ( + {"max_length": -1, "array": 42, "num_positive": 10, "num_negative": 0}, + r"max_length", + ), + ( + {"max_length": 2, "array": 4, "num_positive": 10, "num_negative": 0}, + r"array", + ), + ( + {"max_length": 8, "array": 42, "num_positive": -1, "num_negative": 0}, + r"num_positive", + ), + ( + {"max_length": 8, "array": 42, "num_positive": 10, "num_negative": -1}, + r"num_negative", + ), + ), + ) + def test_validate_negative(data_: dict, error_regex: str) -> None: + """Negative tests for the `_validate` method.""" + with pytest.raises((TypeError, ValueError), match=error_regex): + AvailabilityWindow._validate(data_) + + @staticmethod + @given(availability_window_data()) + def test_validate_positive(data_: Dict[str, int]) -> None: + """Positive tests for the `_validate` method.""" + AvailabilityWindow._validate(data_) + + @staticmethod + @given(availability_window_data()) + def test_from_dict(data_: Dict[str, int]) -> None: + """Test `from_dict` method.""" + availability_window = AvailabilityWindow.from_dict(data_) + + # convert the serialized array to a binary string + binary_number = bin(data_["array"])[2:] + # convert each character in the binary string to a flag + flags = [bool(int(digit)) for digit in binary_number] + expected_window = deque(flags, maxlen=data_["max_length"]) + + assert availability_window._max_length == data_["max_length"] + assert availability_window._window == expected_window + assert availability_window._num_positive == data_["num_positive"] + assert availability_window._num_negative == data_["num_negative"] + + @staticmethod + @given(availability_window_data()) + def test_to_dict_and_back(data_: Dict[str, int]) -> None: + """Test that the `from_dict` produces an object that generates the input data again when calling `to_dict`.""" + availability_window = AvailabilityWindow.from_dict(data_) + assert availability_window.to_dict() == data_ + + +class TestOffenceStatus: + """Test the `OffenceStatus` dataclass.""" + + @staticmethod + @pytest.mark.parametrize("light_unit_amount, serious_unit_amount", ((1, 2),)) + @pytest.mark.parametrize( + "validator_downtime, invalid_payload, blacklisted, suspected, " + "num_unknown_offenses, num_double_signed, num_light_client_attack, expected", + ( + (False, False, False, False, 0, 0, 0, 0), + (True, False, False, False, 0, 0, 0, 1), + (False, True, False, False, 0, 0, 0, 1), + (False, False, True, False, 0, 0, 0, 1), + (False, False, False, True, 0, 0, 0, 1), + (False, False, False, False, 1, 0, 0, 2), + (False, False, False, False, 0, 1, 0, 2), + (False, False, False, False, 0, 0, 1, 2), + (False, False, False, False, 0, 2, 1, 6), + (False, True, False, True, 5, 2, 1, 18), + (True, True, True, True, 5, 2, 1, 20), + ), + ) + def test_slash_amount( + light_unit_amount: int, + serious_unit_amount: int, + validator_downtime: bool, + invalid_payload: bool, + blacklisted: bool, + suspected: bool, + num_unknown_offenses: int, + num_double_signed: int, + num_light_client_attack: int, + expected: int, + ) -> None: + """Test the `slash_amount` method.""" + status = OffenceStatus() + + if validator_downtime: + for _ in range(abci_base.NUMBER_OF_BLOCKS_TRACKED): + status.validator_downtime.add(True) + + for _ in range(abci_base.NUMBER_OF_ROUNDS_TRACKED): + if invalid_payload: + status.invalid_payload.add(True) + if blacklisted: + status.blacklisted.add(True) + if suspected: + status.suspected.add(True) + + status.num_unknown_offenses = num_unknown_offenses + status.num_double_signed = num_double_signed + status.num_light_client_attack = num_light_client_attack + + actual = status.slash_amount(light_unit_amount, serious_unit_amount) + assert actual == expected + + +@composite +def offence_tracking(draw: DrawFn) -> Tuple[Evidences, LastCommitInfo]: + """A strategy for building offences reported by Tendermint.""" + n_validators = draw(integers(min_value=1, max_value=10)) + + validators = [ + draw( + builds( + Validator, + address=just(bytes(i)), + power=integers(min_value=0), + ) + ) + for i in range(n_validators) + ] + + evidences = builds( + Evidences, + byzantine_validators=lists( + builds( + Evidence, + evidence_type=sampled_from(EvidenceType), + validator=sampled_from(validators), + height=integers(min_value=0), + time=builds( + Timestamp, + seconds=integers(min_value=0), + nanos=integers(min_value=0, max_value=999_999_999), + ), + total_voting_power=integers(min_value=0), + ), + min_size=n_validators, + max_size=n_validators, + unique_by=lambda v: v.validator.address, + ), + ) + + last_commit_info = builds( + LastCommitInfo, + round_=integers(min_value=0), + votes=lists( + builds( + VoteInfo, + validator=sampled_from(validators), + signed_last_block=booleans(), + ), + min_size=n_validators, + max_size=n_validators, + unique_by=lambda v: v.validator.address, + ), + ) + + ev_example, commit_example = draw(evidences), draw(last_commit_info) + + # this assertion proves that all the validators are unique + unique_commit_addresses = set( + v.validator.address.decode() for v in commit_example.votes + ) + assert len(unique_commit_addresses) == n_validators + + # this assertion proves that the same validators are used for evidences and votes + assert unique_commit_addresses == set( + e.validator.address.decode() for e in ev_example.byzantine_validators + ) + + return ev_example, commit_example + + +@composite +def offence_status(draw: DrawFn) -> OffenceStatus: + """Build an offence status instance.""" + validator_downtime = just( + AvailabilityWindow.from_dict(draw(availability_window_data())) + ) + invalid_payload = just( + AvailabilityWindow.from_dict(draw(availability_window_data())) + ) + blacklisted = just(AvailabilityWindow.from_dict(draw(availability_window_data()))) + suspected = just(AvailabilityWindow.from_dict(draw(availability_window_data()))) + + status = builds( + OffenceStatus, + validator_downtime=validator_downtime, + invalid_payload=invalid_payload, + blacklisted=blacklisted, + suspected=suspected, + num_unknown_offenses=integers(min_value=0), + num_double_signed=integers(min_value=0), + num_light_client_attack=integers(min_value=0), + ) + + return draw(status) + + +class TestOffenseStatusEncoderDecoder: + """Test the `OffenseStatusEncoder` and the `OffenseStatusDecoder`.""" + + @staticmethod + @given(dictionaries(keys=text(), values=offence_status(), min_size=1)) + def test_encode_decode_offense_status(offense_status: str) -> None: + """Test encoding an offense status mapping and then decoding it by using the custom encoder/decoder.""" + encoded = json.dumps(offense_status, cls=OffenseStatusEncoder) + decoded = json.loads(encoded, cls=OffenseStatusDecoder) + + assert decoded == offense_status + + def test_encode_unknown(self) -> None: + """Test the encoder with an unknown input.""" + + class Unknown: + """A dummy class that the encoder is not aware of.""" + + unknown = "?" + + with pytest.raises( + TypeError, match="Object of type Unknown is not JSON serializable" + ): + json.dumps(Unknown(), cls=OffenseStatusEncoder) + + class TestRoundSequence: """Test the RoundSequence class.""" def setup(self) -> None: """Set up the test.""" - self.round_sequence = RoundSequence(abci_app_cls=AbciAppTest) - self.round_sequence.setup(MagicMock(), MagicMock()) + self.round_sequence = RoundSequence( + context=MagicMock(), abci_app_cls=AbciAppTest + ) + self.round_sequence.setup(MagicMock(), logging.getLogger()) self.round_sequence.tm_height = 1 + @pytest.mark.parametrize( + "property_name, set_twice_exc, config_exc", + ( + ( + "validator_to_agent", + "The mapping of the validators' addresses to their agent addresses can only be set once. " + "Attempted to set with {new_content_attempt} but it has content already: {value}.", + "The mapping of the validators' addresses to their agent addresses has not been set.", + ), + ), + ) + @given(data()) + def test_slashing_properties( + self, property_name: str, set_twice_exc: str, config_exc: str, _data: Any + ) -> None: + """Test `validator_to_agent` getter and setter.""" + if property_name == "validator_to_agent": + data_generator = dictionaries(text(), text()) + else: + data_generator = dictionaries(text(), just(OffenceStatus())) + + value = _data.draw(data_generator) + round_sequence = RoundSequence(context=MagicMock(), abci_app_cls=AbciAppTest) + + if value: + setattr(round_sequence, property_name, value) + assert getattr(round_sequence, property_name) == value + new_content_attempt = _data.draw(data_generator) + with pytest.raises( + ValueError, + match=re.escape( + set_twice_exc.format( + new_content_attempt=new_content_attempt, value=value + ) + ), + ): + setattr(round_sequence, property_name, new_content_attempt) + return + + with pytest.raises(SlashingNotConfiguredError, match=config_exc): + getattr(round_sequence, property_name) + + @mock.patch("json.loads", return_value="json_serializable") + @pytest.mark.parametrize("slashing_config", (None, "", "test")) + def test_sync_db_and_slashing( + self, mock_loads: mock.MagicMock, slashing_config: str + ) -> None: + """Test the `sync_db_and_slashing` method.""" + self.round_sequence.latest_synchronized_data.slashing_config = slashing_config + serialized_db_state = "dummy_db_state" + self.round_sequence.sync_db_and_slashing(serialized_db_state) + + # Check that `sync()` was called with the correct arguments + mock_sync = cast( + mock.Mock, self.round_sequence.abci_app.synchronized_data.db.sync + ) + mock_sync.assert_called_once_with(serialized_db_state) + + if slashing_config: + mock_loads.assert_called_once_with( + slashing_config, cls=OffenseStatusDecoder + ) + else: + mock_loads.assert_not_called() + + @mock.patch("json.dumps") + def test_store_offence_status(self, mock_dumps: mock.MagicMock) -> None: + """Test the `store_offence_status` method.""" + # Set up mock objects and return values + self.round_sequence._offence_status = {"not_encoded": OffenceStatus()} + mock_encoded_status = "encoded_status" + mock_dumps.return_value = mock_encoded_status + + # Call the method to be tested + self.round_sequence.store_offence_status() + + # Check that `json.dumps()` was called with the correct arguments + mock_dumps.assert_called_once_with( + self.round_sequence.offence_status, cls=OffenseStatusEncoder, sort_keys=True + ) + + assert ( + self.round_sequence.abci_app.synchronized_data.db.slashing_config + == mock_encoded_status + ) + + @given( + validator=builds(Validator, address=binary(), power=integers()), + agent_address=text(), + ) + def test_get_agent_address(self, validator: Validator, agent_address: str) -> None: + """Test `get_agent_address` method.""" + round_sequence = RoundSequence(context=MagicMock(), abci_app_cls=AbciAppTest) + round_sequence.validator_to_agent = { + validator.address.hex().upper(): agent_address + } + assert round_sequence.get_agent_address(validator) == agent_address + + unknown = deepcopy(validator) + unknown.address += b"unknown" + with pytest.raises( + ValueError, + match=re.escape( + f"Requested agent address for an unknown validator address {unknown.address.hex().upper()}. " + f"Available validators are: {round_sequence.validator_to_agent.keys()}" + ), + ): + round_sequence.get_agent_address(unknown) + @pytest.mark.parametrize("offset", tuple(range(5))) @pytest.mark.parametrize("n_blocks", (0, 1, 10)) def test_height(self, n_blocks: int, offset: int) -> None: @@ -1876,7 +2520,9 @@ def test_latest_result(self) -> None: def test_last_round_transition_timestamp(self, committed: bool) -> None: """Test 'last_round_transition_timestamp' method.""" if committed: - self.round_sequence.begin_block(MagicMock(height=1)) + self.round_sequence.begin_block( + MagicMock(height=1), MagicMock(), MagicMock() + ) self.round_sequence.end_block() self.round_sequence.commit() assert ( @@ -1895,7 +2541,9 @@ def test_last_round_transition_timestamp(self, committed: bool) -> None: def test_last_round_transition_height(self, committed: bool) -> None: """Test 'last_round_transition_height' method.""" if committed: - self.round_sequence.begin_block(MagicMock(height=1)) + self.round_sequence.begin_block( + MagicMock(height=1), MagicMock(), MagicMock() + ) self.round_sequence.end_block() self.round_sequence.commit() assert ( @@ -1914,12 +2562,13 @@ def test_last_round_transition_height(self, committed: bool) -> None: def test_block_before_blockchain_is_init(self, caplog: LogCaptureFixture) -> None: """Test block received before blockchain initialized.""" - self.round_sequence.begin_block(MagicMock(height=1)) + self.round_sequence.begin_block(MagicMock(height=1), MagicMock(), MagicMock()) self.round_sequence.end_block() blockchain = self.round_sequence.blockchain blockchain._is_init = False self.round_sequence.blockchain = blockchain - self.round_sequence.commit() + with caplog.at_level(logging.INFO): + self.round_sequence.commit() expected = "Received block with height 1 before the blockchain was initialized." assert expected in caplog.text @@ -1958,7 +2607,9 @@ def test_last_round_transition_tm_height(self, tm_height: Optional[int]) -> None _ = self.round_sequence.last_round_transition_tm_height else: self.round_sequence.tm_height = tm_height - self.round_sequence.begin_block(MagicMock(height=1)) + self.round_sequence.begin_block( + MagicMock(height=1), MagicMock(), MagicMock() + ) self.round_sequence.end_block() self.round_sequence.commit() assert self.round_sequence.last_round_transition_tm_height == tm_height @@ -2009,6 +2660,126 @@ def test_init_chain(self, begin_height: int, initial_height: int) -> None: self.round_sequence.init_chain(initial_height) assert self.round_sequence._blockchain.height == initial_height - 1 + @given(offence_tracking()) + @settings(suppress_health_check=[HealthCheck.too_slow]) + def test_track_tm_offences( + self, offences: Tuple[Evidences, LastCommitInfo] + ) -> None: + """Test `_track_tm_offences` method.""" + evidences, last_commit_info = offences + dummy_addr_template = "agent_{i}" + round_sequence = RoundSequence(context=MagicMock(), abci_app_cls=AbciAppTest) + synchronized_data_mock = MagicMock() + round_sequence.setup(synchronized_data_mock, MagicMock()) + round_sequence.enable_slashing() + + expected_offence_status = { + dummy_addr_template.format(i=i): OffenceStatus() + for i in range(len(last_commit_info.votes)) + } + for i, vote_info in enumerate(last_commit_info.votes): + agent_address = dummy_addr_template.format(i=i) + # initialize dummy round sequence's offence status and validator to agent address mapping + round_sequence._offence_status[agent_address] = OffenceStatus() + validator_address = vote_info.validator.address.hex() + round_sequence._validator_to_agent[validator_address] = agent_address + # set expected result + expected_was_down = not vote_info.signed_last_block + expected_offence_status[agent_address].validator_downtime.add( + expected_was_down + ) + + for byzantine_validator in evidences.byzantine_validators: + agent_address = round_sequence._validator_to_agent[ + byzantine_validator.validator.address.hex() + ] + evidence_type = byzantine_validator.evidence_type + expected_offence_status[agent_address].num_unknown_offenses += bool( + evidence_type == EvidenceType.UNKNOWN + ) + expected_offence_status[agent_address].num_double_signed += bool( + evidence_type == EvidenceType.DUPLICATE_VOTE + ) + expected_offence_status[agent_address].num_light_client_attack += bool( + evidence_type == EvidenceType.LIGHT_CLIENT_ATTACK + ) + + round_sequence._track_tm_offences(evidences, last_commit_info) + assert round_sequence._offence_status == expected_offence_status + + @mock.patch.object(abci_base, "ADDRESS_LENGTH", len("agent_i")) + def test_track_app_offences(self) -> None: + """Test `_track_app_offences` method.""" + dummy_addr_template = "agent_{i}" + stub_offending_keepers = [dummy_addr_template.format(i=i) for i in range(2)] + self.round_sequence.enable_slashing() + self.round_sequence._offence_status = { + dummy_addr_template.format(i=i): OffenceStatus() for i in range(4) + } + expected_offence_status = deepcopy(self.round_sequence._offence_status) + + for i in (dummy_addr_template.format(i=i) for i in range(4)): + offended = i in stub_offending_keepers + expected_offence_status[i].blacklisted.add(offended) + expected_offence_status[i].suspected.add(offended) + + with mock.patch.object( + self.round_sequence.latest_synchronized_data.db, + "get", + return_value="".join(stub_offending_keepers), + ): + self.round_sequence._track_app_offences() + assert self.round_sequence._offence_status == expected_offence_status + + @given(builds(SlashingNotConfiguredError, text())) + def test_handle_slashing_not_configured( + self, exc: SlashingNotConfiguredError + ) -> None: + """Test `_handle_slashing_not_configured` method.""" + logging.disable(logging.CRITICAL) + + round_sequence = RoundSequence(context=MagicMock(), abci_app_cls=AbciAppTest) + round_sequence.setup(MagicMock(), MagicMock()) + + assert not round_sequence._slashing_enabled + assert round_sequence.latest_synchronized_data.nb_participants == 0 + round_sequence._handle_slashing_not_configured(exc) + assert not round_sequence._slashing_enabled + + with mock.patch.object( + round_sequence.latest_synchronized_data.db, + "get", + return_value=[i for i in range(4)], + ): + assert round_sequence.latest_synchronized_data.nb_participants == 4 + round_sequence._handle_slashing_not_configured(exc) + assert not round_sequence._slashing_enabled + + logging.disable(logging.NOTSET) + + @pytest.mark.parametrize("_track_offences_raises", (True, False)) + def test_try_track_offences(self, _track_offences_raises: bool) -> None: + """Test `_try_track_offences` method.""" + evidences, last_commit_info = MagicMock(), MagicMock() + self.round_sequence.enable_slashing() + with mock.patch.object( + self.round_sequence, + "_track_app_offences", + ), mock.patch.object( + self.round_sequence, + "_track_tm_offences", + side_effect=SlashingNotConfiguredError if _track_offences_raises else None, + ) as _track_offences_mock, mock.patch.object( + self.round_sequence, "_handle_slashing_not_configured" + ) as _handle_slashing_not_configured_mock: + self.round_sequence._try_track_offences(evidences, last_commit_info) + if _track_offences_raises: + _handle_slashing_not_configured_mock.assert_called_once() + else: + _track_offences_mock.assert_called_once_with( + evidences, last_commit_info + ) + def test_begin_block_negative_is_finished(self) -> None: """Test 'begin_block' method, negative case (round sequence is finished).""" self.round_sequence.abci_app._current_round = None @@ -2016,7 +2787,7 @@ def test_begin_block_negative_is_finished(self) -> None: ABCIAppInternalError, match="internal error: round sequence is finished, cannot accept new blocks", ): - self.round_sequence.begin_block(MagicMock()) + self.round_sequence.begin_block(MagicMock(), MagicMock(), MagicMock()) def test_begin_block_negative_wrong_phase(self) -> None: """Test 'begin_block' method, negative case (wrong phase).""" @@ -2025,11 +2796,11 @@ def test_begin_block_negative_wrong_phase(self) -> None: ABCIAppInternalError, match="internal error: cannot accept a 'begin_block' request.", ): - self.round_sequence.begin_block(MagicMock()) + self.round_sequence.begin_block(MagicMock(), MagicMock(), MagicMock()) def test_begin_block_positive(self) -> None: """Test 'begin_block' method, positive case.""" - self.round_sequence.begin_block(MagicMock()) + self.round_sequence.begin_block(MagicMock(), MagicMock(), MagicMock()) def test_deliver_tx_negative_wrong_phase(self) -> None: """Test 'begin_block' method, negative (wrong phase).""" @@ -2041,7 +2812,7 @@ def test_deliver_tx_negative_wrong_phase(self) -> None: def test_deliver_tx_positive_not_valid(self) -> None: """Test 'begin_block' method, positive (not valid).""" - self.round_sequence.begin_block(MagicMock()) + self.round_sequence.begin_block(MagicMock(), MagicMock(), MagicMock()) with mock.patch.object( self.round_sequence.current_round, "check_transaction", return_value=True ): @@ -2060,7 +2831,7 @@ def test_end_block_negative_wrong_phase(self) -> None: def test_end_block_positive(self) -> None: """Test 'end_block' method, positive case.""" - self.round_sequence.begin_block(MagicMock()) + self.round_sequence.begin_block(MagicMock(), MagicMock(), MagicMock()) self.round_sequence.end_block() def test_commit_negative_wrong_phase(self) -> None: @@ -2073,7 +2844,7 @@ def test_commit_negative_wrong_phase(self) -> None: def test_commit_negative_exception(self) -> None: """Test 'end_block' method, negative case (raise exception).""" - self.round_sequence.begin_block(MagicMock(height=1)) + self.round_sequence.begin_block(MagicMock(height=1), MagicMock(), MagicMock()) self.round_sequence.end_block() with mock.patch.object( self.round_sequence._blockchain, "add_block", side_effect=AddBlockError @@ -2083,7 +2854,7 @@ def test_commit_negative_exception(self) -> None: def test_commit_positive_no_change_round(self) -> None: """Test 'end_block' method, positive (no change round).""" - self.round_sequence.begin_block(MagicMock(height=1)) + self.round_sequence.begin_block(MagicMock(height=1), MagicMock(), MagicMock()) self.round_sequence.end_block() with mock.patch.object( self.round_sequence.current_round, @@ -2094,7 +2865,7 @@ def test_commit_positive_no_change_round(self) -> None: def test_commit_positive_with_change_round(self) -> None: """Test 'end_block' method, positive (with change round).""" - self.round_sequence.begin_block(MagicMock(height=1)) + self.round_sequence.begin_block(MagicMock(height=1), MagicMock(), MagicMock()) self.round_sequence.end_block() round_result, next_round = MagicMock(), MagicMock() with mock.patch.object( @@ -2119,68 +2890,87 @@ def test_reset_blockchain(self, is_replay: bool) -> None: ) assert self.round_sequence._blockchain.height == 0 + def last_round_values_updated(self, any_: bool = True) -> bool: + """Check if the values for the last round-related attributes have been updated.""" + seq = self.round_sequence + + current_last_pairs = ( + ( + seq._blockchain.last_block.timestamp, + seq._last_round_transition_timestamp, + ), + (seq._blockchain.height, seq._last_round_transition_height), + (seq.root_hash, seq._last_round_transition_root_hash), + (seq.tm_height, seq._last_round_transition_tm_height), + ) + + if any_: + return any(current == last for current, last in current_last_pairs) + + return all(current == last for current, last in current_last_pairs) + @mock.patch.object(AbciApp, "process_event") + @mock.patch.object(RoundSequence, "store_offence_status") @pytest.mark.parametrize("end_block_res", (None, (MagicMock(), MagicMock()))) + @pytest.mark.parametrize( + "slashing_enabled, offence_status_", + ( + ( + False, + False, + ), + ( + False, + True, + ), + ( + False, + False, + ), + ( + True, + True, + ), + ), + ) def test_update_round( self, + store_offence_status_mock: mock.Mock, process_event_mock: mock.Mock, end_block_res: Optional[Tuple[BaseSynchronizedData, Any]], + slashing_enabled: bool, + offence_status_: dict, ) -> None: """Test '_update_round' method.""" - self.round_sequence.begin_block(MagicMock(height=1)) + self.round_sequence.begin_block(MagicMock(height=1), MagicMock(), MagicMock()) block = self.round_sequence._block_builder.get_block() self.round_sequence._blockchain.add_block(block) + self.round_sequence._slashing_enabled = slashing_enabled + self.round_sequence._offence_status = offence_status_ with mock.patch.object( self.round_sequence.current_round, "end_block", return_value=end_block_res - ), mock.patch.object( - self.round_sequence.abci_app, "_is_termination_set", return_value=False ): self.round_sequence._update_round() if end_block_res is None: - assert ( - self.round_sequence._last_round_transition_timestamp - != self.round_sequence._blockchain.last_block.timestamp - ) - assert ( - self.round_sequence._last_round_transition_height - != self.round_sequence._blockchain.height - ) - assert ( - self.round_sequence._last_round_transition_root_hash - != self.round_sequence.root_hash - ) - assert ( - self.round_sequence._last_round_transition_tm_height - != self.round_sequence.tm_height - ) + assert not self.last_round_values_updated() process_event_mock.assert_not_called() + return + assert self.last_round_values_updated(any_=False) + process_event_mock.assert_called_with( + end_block_res[-1], result=end_block_res[0] + ) + + if slashing_enabled: + store_offence_status_mock.assert_called_once() else: - assert ( - self.round_sequence._last_round_transition_timestamp - == self.round_sequence._blockchain.last_block.timestamp - ) - assert ( - self.round_sequence._last_round_transition_height - == self.round_sequence._blockchain.height - ) - assert ( - self.round_sequence._last_round_transition_root_hash - == self.round_sequence.root_hash - ) - assert ( - self.round_sequence._last_round_transition_tm_height - == self.round_sequence.tm_height - ) - process_event_mock.assert_called_with( - end_block_res[-1], result=end_block_res[0] - ) + store_offence_status_mock.assert_not_called() @mock.patch.object(AbciApp, "process_event") @pytest.mark.parametrize( - "background_round_result, current_round_result", + "termination_round_result, current_round_result", [ (None, None), (None, (MagicMock(), MagicMock())), @@ -2188,29 +2978,31 @@ def test_update_round( ((MagicMock(), MagicMock()), (MagicMock(), MagicMock())), ], ) - def test_update_round_when_background_returns( + def test_update_round_when_termination_returns( self, process_event_mock: mock.Mock, - background_round_result: Optional[Tuple[BaseSynchronizedData, Any]], + termination_round_result: Optional[Tuple[BaseSynchronizedData, Any]], current_round_result: Optional[Tuple[BaseSynchronizedData, Any]], ) -> None: """Test '_update_round' method.""" - self.round_sequence.begin_block(MagicMock(height=1)) + self.round_sequence.begin_block(MagicMock(height=1), MagicMock(), MagicMock()) block = self.round_sequence._block_builder.get_block() self.round_sequence._blockchain.add_block(block) + self.round_sequence.abci_app.add_background_app(STUB_TERMINATION_CONFIG) + self.round_sequence.abci_app.setup() with mock.patch.object( self.round_sequence.current_round, "end_block", return_value=current_round_result, ), mock.patch.object( - self.round_sequence.background_round, + ConcreteBackgroundRound, "end_block", - return_value=background_round_result, + return_value=termination_round_result, ): self.round_sequence._update_round() - if background_round_result is None and current_round_result is None: + if termination_round_result is None and current_round_result is None: assert ( self.round_sequence._last_round_transition_timestamp != self.round_sequence._blockchain.last_block.timestamp @@ -2228,7 +3020,7 @@ def test_update_round_when_background_returns( != self.round_sequence.tm_height ) process_event_mock.assert_not_called() - elif background_round_result is None and current_round_result is not None: + elif termination_round_result is None and current_round_result is not None: assert ( self.round_sequence._last_round_transition_timestamp == self.round_sequence._blockchain.last_block.timestamp @@ -2249,7 +3041,7 @@ def test_update_round_when_background_returns( current_round_result[-1], result=current_round_result[0], ) - elif background_round_result is not None: + elif termination_round_result is not None: assert ( self.round_sequence._last_round_transition_timestamp == self.round_sequence._blockchain.last_block.timestamp @@ -2267,25 +3059,28 @@ def test_update_round_when_background_returns( == self.round_sequence.tm_height ) process_event_mock.assert_called_with( - background_round_result[-1], - result=background_round_result[0], + termination_round_result[-1], + result=termination_round_result[0], ) - @mock.patch.object(AbciAppDB, "sync") + self.round_sequence.abci_app.background_apps.clear() + @pytest.mark.parametrize("restart_from_round", (ConcreteRoundA, MagicMock())) @pytest.mark.parametrize("serialized_db_state", (None, "serialized state")) + @given(integers()) def test_reset_state( self, - _: mock._patch, restart_from_round: AbstractRound, serialized_db_state: str, + round_count: int, ) -> None: """Tests reset_state""" - round_count = 1 with mock.patch.object( self.round_sequence, "_reset_to_default_params", - ) as mock_reset: + ) as mock_reset, mock.patch.object( + self.round_sequence, "sync_db_and_slashing" + ) as mock_sync_db_and_slashing: transition_fn = self.round_sequence.abci_app.transition_function round_id = restart_from_round.auto_round_id() if restart_from_round in transition_fn: @@ -2293,6 +3088,19 @@ def test_reset_state( round_id, round_count, serialized_db_state ) mock_reset.assert_called() + + if serialized_db_state is None: + mock_sync_db_and_slashing.assert_not_called() + + else: + mock_sync_db_and_slashing.assert_called_once_with( + serialized_db_state + ) + assert ( + self.round_sequence._last_round_transition_root_hash + == self.round_sequence.root_hash + ) + else: round_ids = {cls.auto_round_id() for cls in transition_fn} with pytest.raises( @@ -2318,6 +3126,8 @@ def test_reset_to_default_params(self) -> None: self.round_sequence._last_round_transition_root_hash = MagicMock() self.round_sequence._last_round_transition_tm_height = MagicMock() self.round_sequence._tm_height = MagicMock() + self._pending_offences = MagicMock() + self._slashing_enabled = MagicMock() # we reset them self.round_sequence._reset_to_default_params() @@ -2328,6 +3138,15 @@ def test_reset_to_default_params(self) -> None: assert self.round_sequence._last_round_transition_root_hash == b"" assert self.round_sequence._last_round_transition_tm_height is None assert self.round_sequence._tm_height is None + assert self.round_sequence.pending_offences == set() + assert not self.round_sequence._slashing_enabled + + def test_add_pending_offence(self) -> None: + """Tests add_pending_offence.""" + assert self.round_sequence.pending_offences == set() + mock_offence = MagicMock() + self.round_sequence.add_pending_offence(mock_offence) + assert self.round_sequence.pending_offences == {mock_offence} def test_meta_abci_app_when_instance_not_subclass_of_abstract_round() -> None: @@ -2392,7 +3211,7 @@ def dummy_attr(self) -> object: with mock.patch.object(AbciAppTest, "initial_round_cls") as m: m.synchronized_data_class = SynchronizedData - abci_app = AbciAppTest(synchronized_data, logging.getLogger()) + abci_app = AbciAppTest(synchronized_data, logging.getLogger(), MagicMock()) abci_app.setup() assert isinstance(abci_app.synchronized_data, SynchronizedData) assert abci_app.synchronized_data.dummy_attr == sentinel @@ -2410,3 +3229,117 @@ def some_property(self) -> Any: assert get_name(SomeObject.some_property) == "some_property" with pytest.raises(ValueError, match="1 is not a property"): get_name(1) + + +@pytest.mark.parametrize( + "sender, accused_agent_address, offense_round, offense_type_value, last_transition_timestamp, time_to_live", + ( + ( + "sender", + "test_address", + 90, + 3, + 10, + 2, + ), + ), +) +def test_pending_offences_payload( + sender: str, + accused_agent_address: str, + offense_round: int, + offense_type_value: int, + last_transition_timestamp: int, + time_to_live: int, +) -> None: + """Test `PendingOffencesPayload`""" + + payload = abci_base.PendingOffencesPayload( + sender, + accused_agent_address, + offense_round, + offense_type_value, + last_transition_timestamp, + time_to_live, + ) + + assert payload.id_ + assert payload.round_count == abci_base.ROUND_COUNT_DEFAULT + assert payload.sender == sender + assert payload.accused_agent_address == accused_agent_address + assert payload.offense_round == offense_round + assert payload.offense_type_value == offense_type_value + assert payload.last_transition_timestamp == last_transition_timestamp + assert payload.time_to_live == time_to_live + assert payload.data == { + "accused_agent_address": accused_agent_address, + "offense_round": offense_round, + "offense_type_value": offense_type_value, + "last_transition_timestamp": last_transition_timestamp, + "time_to_live": time_to_live, + } + + +class TestPendingOffencesRound(BaseRoundTestClass): + """Tests for `PendingOffencesRound`.""" + + _synchronized_data_class = BaseSynchronizedData + + @given( + accused_agent_address=sampled_from(list(get_participants())), + offense_round=integers(min_value=0), + offense_type_value=sampled_from( + [value.value for value in OffenseType.__members__.values()] + ), + last_transition_timestamp=floats( + min_value=timegm(datetime.datetime(1971, 1, 1).utctimetuple()), + max_value=timegm(datetime.datetime(8000, 1, 1).utctimetuple()) - 2000, + ), + time_to_live=floats(min_value=1, max_value=2000), + ) + def test_run( + self, + accused_agent_address: str, + offense_round: int, + offense_type_value: int, + last_transition_timestamp: float, + time_to_live: float, + ) -> None: + """Run tests.""" + + test_round = abci_base.PendingOffencesRound( + synchronized_data=self.synchronized_data, + context=MagicMock(), + ) + # initialize the offence status + status_initialization = dict.fromkeys(self.participants, OffenceStatus()) + test_round.context.state.round_sequence.offence_status = status_initialization + + # create the actual and expected value + actual = test_round.context.state.round_sequence.offence_status + expected_invalid = offense_type_value == OffenseType.INVALID_PAYLOAD.value + expected = deepcopy(status_initialization) + + first_payload, *payloads = [ + abci_base.PendingOffencesPayload( + sender, + accused_agent_address, + offense_round, + offense_type_value, + last_transition_timestamp, + time_to_live, + ) + for sender in self.participants + ] + + test_round.process_payload(first_payload) + assert test_round.collection == {first_payload.sender: first_payload} + test_round.end_block() + assert actual == expected + + for payload in payloads: + test_round.process_payload(payload) + test_round.end_block() + + expected[accused_agent_address].invalid_payload.add(expected_invalid) + assert actual == expected diff --git a/packages/valory/skills/abstract_round_abci/tests/test_base_rounds.py b/packages/valory/skills/abstract_round_abci/tests/test_base_rounds.py index 1df770b768..06da2581fb 100644 --- a/packages/valory/skills/abstract_round_abci/tests/test_base_rounds.py +++ b/packages/valory/skills/abstract_round_abci/tests/test_base_rounds.py @@ -24,6 +24,7 @@ import re from enum import Enum from typing import FrozenSet, List, Optional, Tuple, Union, cast +from unittest.mock import MagicMock import pytest @@ -60,7 +61,9 @@ def setup( """Setup test.""" super().setup() - self.test_round = DummyCollectionRound(synchronized_data=self.synchronized_data) + self.test_round = DummyCollectionRound( + synchronized_data=self.synchronized_data, context=MagicMock() + ) def test_serialized_collection(self) -> None: """Test `serialized_collection` property.""" @@ -148,6 +151,7 @@ def test_run( test_round = DummyCollectDifferentUntilAllRound( synchronized_data=self.synchronized_data, + context=MagicMock(), ) round_id = DummyCollectDifferentUntilAllRound.auto_round_id() @@ -198,6 +202,7 @@ def test_run( test_round = DummyCollectSameUntilAllRound( synchronized_data=self.synchronized_data, + context=MagicMock(), ) round_id = DummyCollectSameUntilAllRound.auto_round_id() @@ -271,6 +276,7 @@ def test_run( test_round = DummyCollectSameUntilThresholdRound( synchronized_data=self.synchronized_data, + context=MagicMock(), ) test_round.collection_key = "dummy_collection_key" test_round.selection_key = selection_key @@ -323,6 +329,7 @@ def test_run_with_none( test_round = DummyCollectSameUntilThresholdRound( synchronized_data=self.synchronized_data, + context=MagicMock(), ) first_payload, *payloads = get_dummy_tx_payloads( @@ -359,6 +366,7 @@ def test_run( synchronized_data=self.synchronized_data.update( most_voted_keeper_address="agent_0" ), + context=MagicMock(), ) assert test_round.keeper_payload is None @@ -421,6 +429,7 @@ def test_keeper_payload_is_none( synchronized_data=self.synchronized_data.update( most_voted_keeper_address=keeper, ), + context=MagicMock(), ), keeper_payloads=DummyTxPayload(keeper, None), synchronized_data_update_fn=lambda _synchronized_data, _test_round: _synchronized_data, @@ -437,6 +446,7 @@ def setup_test_voting_round(self) -> DummyVotingRound: """Setup test voting round""" return DummyVotingRound( synchronized_data=self.synchronized_data, + context=MagicMock(), ) def test_vote_count(self) -> None: @@ -529,6 +539,7 @@ def test_run( test_round = DummyCollectDifferentUntilThresholdRound( synchronized_data=self.synchronized_data, + context=MagicMock(), ) test_round.block_confirmations = 0 test_round.required_block_confirmations = required_confirmations @@ -568,6 +579,7 @@ def test_end_round(self) -> None: test_round = DummyCollectDifferentUntilThresholdRound( synchronized_data=self.synchronized_data, + context=MagicMock(), ) test_round.collection_key = "dummy_collection_key" test_round.done_event = DummyEvent.DONE @@ -587,6 +599,7 @@ def test_get_non_empty_values(self) -> None: """Test `_get_non_empty_values`.""" test_round = DummyCollectNonEmptyUntilThresholdRound( synchronized_data=self.synchronized_data, + context=MagicMock(), ) payloads = get_dummy_tx_payloads(self.participants) none_payload_idx = 3 @@ -608,6 +621,7 @@ def test_process_payload(self) -> None: """Test `process_payload`.""" test_round = DummyCollectNonEmptyUntilThresholdRound( synchronized_data=self.synchronized_data, + context=MagicMock(), ) first_payload, *payloads = get_dummy_tx_payloads(self.participants) test_round.process_payload(first_payload) @@ -635,6 +649,7 @@ def test_end_block( """Test `end_block` when collection threshold is reached.""" test_round = DummyCollectNonEmptyUntilThresholdRound( synchronized_data=self.synchronized_data, + context=MagicMock(), ) test_round.selection_key = selection_key payloads = get_dummy_tx_payloads( diff --git a/packages/valory/skills/abstract_round_abci/tests/test_behaviours.py b/packages/valory/skills/abstract_round_abci/tests/test_behaviours.py index 0de373b19f..4c0117df5b 100644 --- a/packages/valory/skills/abstract_round_abci/tests/test_behaviours.py +++ b/packages/valory/skills/abstract_round_abci/tests/test_behaviours.py @@ -18,16 +18,20 @@ # ------------------------------------------------------------------------------ """Test the behaviours.py module of the skill.""" - # pylint: skip-file +import platform from abc import ABC +from calendar import timegm +from datetime import datetime from pathlib import Path from typing import Any, Dict, Generator, Optional, Tuple from unittest import mock from unittest.mock import MagicMock import pytest +from hypothesis import given, settings +from hypothesis import strategies as st from packages.valory.skills.abstract_round_abci import PUBLIC_ID from packages.valory.skills.abstract_round_abci.base import ( @@ -38,6 +42,8 @@ BaseTxPayload, DegenerateRound, EventType, + OffenseType, + PendingOffense, RoundSequence, ) from packages.valory.skills.abstract_round_abci.behaviour_utils import ( @@ -47,9 +53,11 @@ ) from packages.valory.skills.abstract_round_abci.behaviours import ( AbstractRoundBehaviour, + PendingOffencesBehaviour, _MetaRoundBehaviour, ) from packages.valory.skills.abstract_round_abci.models import TendermintRecoveryParams +from packages.valory.skills.abstract_round_abci.tests.conftest import profile_name BEHAVIOUR_A_ID = "behaviour_a" @@ -61,6 +69,9 @@ CONCRETE_BACKGROUND_ROUND_ID = "background_round" +settings.load_profile(profile_name) + + def test_skill_public_id() -> None: """Test skill module public ID""" @@ -193,7 +204,7 @@ class ConcreteRoundBehaviour(AbstractRoundBehaviour): abci_app_cls = ConcreteAbciApp behaviours = {BehaviourA, BehaviourB} # type: ignore initial_behaviour_cls = BehaviourA - background_behaviour_cls = ConcreteBackgroundBehaviour + background_behaviours_cls = {ConcreteBackgroundBehaviour} # type: ignore class TestAbstractRoundBehaviour: @@ -207,20 +218,20 @@ def setup(self) -> None: context_mock.state.round_sequence.syncing_up = False self.round_sequence_mock.block_stall_deadline_expired = False self.behaviour = ConcreteRoundBehaviour(name="", skill_context=context_mock) - self.behaviour.tm_manager = self.behaviour.instantiate_behaviour_cls(TmManager) # type: ignore @pytest.mark.parametrize("use_termination", (True, False)) def test_setup(self, use_termination: bool) -> None: """Test 'setup' method.""" - assert self.behaviour.background_behaviour is None + assert self.behaviour.background_behaviours == set() self.behaviour.context.params.use_termination = use_termination self.behaviour.setup() - background_behaviour = self.behaviour.background_behaviour - assert self.behaviour.background_behaviour_cls == ConcreteBackgroundBehaviour + assert self.behaviour.background_behaviours_cls == {ConcreteBackgroundBehaviour} assert ( - isinstance(background_behaviour, self.behaviour.background_behaviour_cls) + isinstance( + self.behaviour.background_behaviours.pop(), ConcreteBackgroundBehaviour + ) if use_termination - else background_behaviour is None + else self.behaviour.background_behaviours == set() ) def test_teardown(self) -> None: @@ -233,6 +244,7 @@ def test_current_behaviour_return_none(self) -> None: def test_act_current_behaviour_name_is_none(self) -> None: """Test 'act' with current behaviour None.""" + self.behaviour.tm_manager = self.behaviour.instantiate_behaviour_cls(TmManager) # type: ignore self.behaviour.current_behaviour = None with mock.patch.object(self.behaviour, "_process_current_round"): self.behaviour.act() @@ -260,7 +272,7 @@ def test_check_matching_round_consistency(self) -> None: class MyRoundBehaviour(AbstractRoundBehaviour): abci_app_cls = MagicMock( - get_all_round_classes=lambda include_termination_rounds: rounds, + get_all_round_classes=lambda _, include_background_rounds: rounds, final_states={ rounds[0], }, @@ -268,6 +280,46 @@ class MyRoundBehaviour(AbstractRoundBehaviour): behaviours = mock_behaviours # type: ignore initial_behaviour_cls = MagicMock() + @pytest.mark.parametrize("behaviour_cls", (set(), {MagicMock()})) + def test_check_matching_round_consistency_with_bg_rounds( + self, behaviour_cls: set + ) -> None: + """Test classmethod '_check_matching_round_consistency' when a background behaviour class is set.""" + rounds = [ + MagicMock(**{"auto_round_id.return_value": f"round_{i}"}) for i in range(3) + ] + mock_behaviours = ( + [ + MagicMock(matching_round=round_, behaviour_id=f"behaviour_{i}") + for i, round_ in enumerate(rounds[1:]) + ] + if behaviour_cls + else [] + ) + + with mock.patch.object( + _MetaRoundBehaviour, "_check_all_required_classattributes_are_set" + ), mock.patch.object( + _MetaRoundBehaviour, "_check_behaviour_id_uniqueness" + ), mock.patch.object( + _MetaRoundBehaviour, "_check_initial_behaviour_in_set_of_behaviours" + ): + + class MyRoundBehaviour(AbstractRoundBehaviour): + abci_app_cls = MagicMock( + get_all_round_classes=lambda _, include_background_rounds: rounds + if include_background_rounds + else [], + final_states={ + rounds[0], + } + if behaviour_cls + else {}, + ) + behaviours = mock_behaviours # type: ignore + initial_behaviour_cls = MagicMock() + background_behaviours_cls = behaviour_cls + def test_get_behaviour_id_to_behaviour_mapping_negative(self) -> None: """Test classmethod '_get_behaviour_id_to_behaviour_mapping', negative case.""" behaviour_id = "behaviour_id" @@ -496,12 +548,14 @@ def test_act_with_round_change(self) -> None: def test_act_with_round_change_after_current_behaviour_is_none(self) -> None: """Test the 'act' method of the behaviour, with round change, after cur behaviour is none.""" + self.behaviour.tm_manager = self.behaviour.instantiate_behaviour_cls(TmManager) # type: ignore self.round_sequence_mock.current_round = RoundA(MagicMock(), MagicMock()) self.round_sequence_mock.current_round_height = 0 # instantiate behaviour - self.behaviour.current_behaviour = self.behaviour.instantiate_behaviour_cls(BehaviourA) # type: ignore - self.behaviour.background_behaviour = self.behaviour.instantiate_behaviour_cls(ConcreteBackgroundBehaviour) # type: ignore + self.behaviour.current_behaviour = self.behaviour.instantiate_behaviour_cls( + BehaviourA + ) with mock.patch.object( self.behaviour.current_behaviour, "clean_up" @@ -544,26 +598,26 @@ def test_act_with_round_change_after_current_behaviour_is_none(self) -> None: new_callable=mock.PropertyMock, return_value=False, ) - @pytest.mark.parametrize("expected_background_acting", (True, False)) - def test_background_behaviour_acting( + @pytest.mark.parametrize("expected_termination_acting", (True, False)) + def test_termination_behaviour_acting( self, _: mock._patch, __: mock._patch, ___: mock._patch, - expected_background_acting: bool, + expected_termination_acting: bool, ) -> None: - """Test if the background behaviour is acting only when it should.""" - self.behaviour.context.params.use_termination = expected_background_acting + """Test if the termination background behaviour is acting only when it should.""" + self.behaviour.context.params.use_termination = expected_termination_acting self.behaviour.setup() - if expected_background_acting: + if expected_termination_acting: with mock.patch.object( - self.behaviour.background_behaviour, + ConcreteBackgroundBehaviour, "act_wrapper", ) as mock_background_act: self.behaviour.act() mock_background_act.assert_called() else: - assert self.behaviour.background_behaviour is None + assert self.behaviour.background_behaviours == set() @mock.patch.object( AbstractRoundBehaviour, @@ -586,6 +640,7 @@ def test_try_fix_call( expected_fix: bool, ) -> None: """Test that `try_fix` is called when necessary.""" + self.behaviour.tm_manager = self.behaviour.instantiate_behaviour_cls(TmManager) # type: ignore with mock.patch.object( TmManager, "tm_communication_unhealthy", @@ -607,14 +662,18 @@ def test_try_fix_call( mock_try_fix.assert_not_called() -def test_meta_round_behaviour_when_instance_not_subclass_of_abstract_round_behaviour() -> None: +def test_meta_round_behaviour_when_instance_not_subclass_of_abstract_round_behaviour() -> ( + None +): """Test instantiation of meta class when instance not a subclass of abstract round behaviour.""" class MyRoundBehaviour(metaclass=_MetaRoundBehaviour): pass -def test_abstract_round_behaviour_instantiation_without_attributes_raises_error() -> None: +def test_abstract_round_behaviour_instantiation_without_attributes_raises_error() -> ( + None +): """Test that definition of concrete subclass of AbstractRoundBehavior without attributes raises error.""" with pytest.raises(ABCIAppInternalError): @@ -651,7 +710,7 @@ class RoundBehaviour(AbstractRoundBehaviour): behaviours = {BehaviourA} initial_behaviour_cls = BehaviourA - round_sequence = RoundSequence(AbciAppTest) + round_sequence = RoundSequence(MagicMock(), AbciAppTest) round_sequence.end_sync() round_sequence.setup(MagicMock(), MagicMock()) context_mock = MagicMock() @@ -697,7 +756,7 @@ class RoundBehaviour(AbstractRoundBehaviour): behaviours = {LongRunningBehaviour} # type: ignore initial_behaviour_cls = LongRunningBehaviour - round_sequence = RoundSequence(AbciAppTest) + round_sequence = RoundSequence(MagicMock(), AbciAppTest) round_sequence.end_sync() round_sequence.setup(MagicMock(), MagicMock()) context_mock = MagicMock() @@ -756,5 +815,84 @@ def dummy_reset_tendermint_with_wait( "reset_tendermint_with_wait", side_effect=dummy_reset_tendermint_with_wait, ) as mock_reset_tendermint: + assert behaviour.tm_manager is not None + behaviour.tm_manager.gentle_reset_attempted = True behaviour.act() mock_reset_tendermint.assert_called() + + +class TestPendingOffencesBehaviour: + """Tests for `PendingOffencesBehaviour`.""" + + behaviour: PendingOffencesBehaviour + + @classmethod + def setup_class(cls) -> None: + """Setup the test class.""" + cls.behaviour = PendingOffencesBehaviour( + name="test", + skill_context=MagicMock(), + ) + + @pytest.mark.skipif( + platform.system() == "Windows", + reason="`timegm` behaves differently on Windows. " + "As a result, the generation of `last_transition_timestamp` is invalid.", + ) + @given( + offence=st.builds( + PendingOffense, + accused_agent_address=st.text(), + round_count=st.integers(min_value=0), + offense_type=st.sampled_from(OffenseType), + last_transition_timestamp=st.floats( + min_value=timegm(datetime(1971, 1, 1).utctimetuple()), + max_value=timegm(datetime(8000, 1, 1).utctimetuple()) - 2000, + ), + time_to_live=st.floats(min_value=1, max_value=2000), + ), + wait_ticks=st.integers(min_value=0, max_value=1000), + expired=st.booleans(), + ) + def test_pending_offences_act( + self, + offence: PendingOffense, + wait_ticks: int, + expired: bool, + ) -> None: + """Test `PendingOffencesBehaviour`.""" + offence_expiration = offence.last_transition_timestamp + offence.time_to_live + offence_expiration += 1 if expired else -1 + self.behaviour.round_sequence.last_round_transition_timestamp = datetime.fromtimestamp( # type: ignore + offence_expiration + ) + + gen = self.behaviour.async_act() + + with mock.patch.object( + self.behaviour, + "send_a2a_transaction", + ) as mock_send_a2a_transaction, mock.patch.object( + self.behaviour, + "wait_until_round_end", + ) as mock_wait_until_round_end, mock.patch.object( + self.behaviour, + "set_done", + ) as mock_set_done: + # while pending offences are empty, the behaviour simply waits + for _ in range(wait_ticks): + next(gen) + + self.behaviour.round_sequence.pending_offences = {offence} + + with pytest.raises(StopIteration): + next(gen) + + check = "assert_not_called" if expired else "assert_called_once" + + for mocked in ( + mock_send_a2a_transaction, + mock_wait_until_round_end, + mock_set_done, + ): + getattr(mocked, check)() diff --git a/packages/valory/skills/abstract_round_abci/tests/test_behaviours_utils.py b/packages/valory/skills/abstract_round_abci/tests/test_behaviours_utils.py index bb5e6b27a1..db30654b0f 100644 --- a/packages/valory/skills/abstract_round_abci/tests/test_behaviours_utils.py +++ b/packages/valory/skills/abstract_round_abci/tests/test_behaviours_utils.py @@ -1273,7 +1273,13 @@ def test_send_transaction_signing_request(self, *_: Any) -> None: ledger_id="ethereum_flashbots", signed_transactions=[{"test_tx": "test_tx"}], ), - kwargs=LedgerApiMessage.Kwargs({}), + kwargs=LedgerApiMessage.Kwargs( + { + "chain_id": None, + "raise_on_failed_simulation": False, + "use_all_builders": True, + } + ), ), ), ( @@ -1286,7 +1292,14 @@ def test_send_transaction_signing_request(self, *_: Any) -> None: ledger_id="ethereum_flashbots", signed_transactions=[{"test_tx": "test_tx"}], ), - kwargs=LedgerApiMessage.Kwargs({"target_block_numbers": [1, 2, 3]}), + kwargs=LedgerApiMessage.Kwargs( + { + "chain_id": None, + "raise_on_failed_simulation": False, + "use_all_builders": True, + "target_block_numbers": [1, 2, 3], + } + ), ), ), ( @@ -2205,6 +2218,12 @@ def dummy_get_status(*_: Any) -> Generator[None, None, MagicMock]: self.behaviour.context.params.tendermint_com_url + "/hard_reset", parameters=expected_parameters, ) + + should_be_healthy = isinstance(reset_response, dict) and reset_response.get( + "status", False + ) + assert self.behaviour._is_healthy is should_be_healthy + # perform the last iteration which also returns the result try: next(reset) @@ -2226,6 +2245,7 @@ def dummy_get_status(*_: Any) -> Generator[None, None, MagicMock]: tm_recovery_params.reset_from_round == self.behaviour.matching_round.auto_round_id() ) + assert not self.behaviour._is_healthy else: pytest.fail("`reset_tendermint_with_wait` did not finish!") @@ -2324,6 +2344,7 @@ def test_async_act(self) -> None: ): self.tm_manager.act_wrapper() + @given(latest_block_height=st.integers(min_value=0)) @pytest.mark.parametrize( "acn_communication_success", ( @@ -2331,6 +2352,13 @@ def test_async_act(self) -> None: False, ), ) + @pytest.mark.parametrize( + "gentle_reset_attempted", + ( + True, + False, + ), + ) @pytest.mark.parametrize( ("tm_reset_success", "num_active_peers"), [ @@ -2342,17 +2370,40 @@ def test_async_act(self) -> None: ) def test_handle_unhealthy_tm( self, + latest_block_height: int, acn_communication_success: bool, + gentle_reset_attempted: bool, tm_reset_success: bool, num_active_peers: Optional[int], ) -> None: """Test _handle_unhealthy_tm.""" + self.tm_manager.gentle_reset_attempted = gentle_reset_attempted + self.tm_manager.context.state.round_sequence.height = latest_block_height + def mock_sleep(_seconds: int) -> Generator: """A method that mocks sleep.""" return yield + def dummy_do_request(*_: Any) -> Generator[None, None, MagicMock]: + """Dummy `_do_request` method.""" + yield + return mock.MagicMock() + + def dummy_get_status(*_: Any) -> Generator[None, None, MagicMock]: + """Dummy `_get_status` method.""" + yield + return mock.MagicMock( + body=json.dumps( + { + "result": { + "sync_info": {"latest_block_height": latest_block_height} + } + } + ).encode() + ) + gen = self.tm_manager._handle_unhealthy_tm() with mock.patch.object( self.tm_manager, @@ -2364,30 +2415,39 @@ def mock_sleep(_seconds: int) -> Generator: side_effect=yield_and_return_int_wrapper(num_active_peers), ), mock.patch.object( self.tm_manager, "sleep", side_effect=mock_sleep - ), mock.patch( - "sys.exit" - ) as mock_sys_exit, mock.patch.object( + ), mock.patch.object( BaseBehaviour, "request_recovery_params", side_effect=dummy_generator_wrapper(acn_communication_success), - ): - next(gen) + ), mock.patch.object( + BaseBehaviour, "_do_request", new_callable=lambda *_: dummy_do_request + ), mock.patch.object( + BaseBehaviour, "_get_status", new_callable=lambda *_: dummy_get_status + ), mock.patch.object( + self.tm_manager.round_sequence, "set_block_stall_deadline" + ) as set_block_stall_deadline_mock: next(gen) + if not gentle_reset_attempted: + next(gen) + assert self.tm_manager.gentle_reset_attempted + with pytest.raises(StopIteration): + next(gen) + set_block_stall_deadline_mock.assert_called_once() + assert not self.tm_manager.gentle_reset_attempted + return + if not acn_communication_success: with pytest.raises(StopIteration): next(gen) + set_block_stall_deadline_mock.assert_not_called() return next(gen) with pytest.raises(StopIteration): next(gen) - if ( - num_active_peers is not None - and num_active_peers < self._DUMMY_CONSENSUS_THRESHOLD - ): - mock_sys_exit.assert_called() + set_block_stall_deadline_mock.assert_not_called() @pytest.mark.parametrize( "expected_reset_params", diff --git a/packages/valory/skills/abstract_round_abci/tests/test_common.py b/packages/valory/skills/abstract_round_abci/tests/test_common.py index 4845aa14eb..427aa81e1d 100644 --- a/packages/valory/skills/abstract_round_abci/tests/test_common.py +++ b/packages/valory/skills/abstract_round_abci/tests/test_common.py @@ -379,7 +379,8 @@ def test_select_keeper( select_keeper_method() return - actual_keeper = select_keeper_method() + with mock.patch("random.seed"): + actual_keeper = select_keeper_method() assert actual_keeper == expected_keeper def test_async_act(self) -> None: diff --git a/packages/valory/skills/abstract_round_abci/tests/test_handlers.py b/packages/valory/skills/abstract_round_abci/tests/test_handlers.py index ad85c0e753..415f11cede 100644 --- a/packages/valory/skills/abstract_round_abci/tests/test_handlers.py +++ b/packages/valory/skills/abstract_round_abci/tests/test_handlers.py @@ -24,6 +24,7 @@ import json import logging from dataclasses import asdict +from datetime import datetime from typing import Any, Dict, cast from unittest import mock from unittest.mock import MagicMock @@ -53,6 +54,7 @@ ERROR_CODE, OK_CODE, SignatureNotValidError, + TransactionNotValidError, ) from packages.valory.skills.abstract_round_abci.dialogues import ( AbciDialogue, @@ -89,6 +91,9 @@ def setup(self) -> None: self.handler = ABCIRoundHandler(name="", skill_context=self.context) self.context.state.round_sequence.height = 0 self.context.state.round_sequence.root_hash = b"root_hash" + self.context.state.round_sequence.last_round_transition_timestamp = ( + datetime.now() + ) def test_info(self) -> None: """Test the 'info' handler method.""" @@ -188,9 +193,14 @@ def test_deliver_tx(self, *_: Any) -> None: performative=AbciMessage.Performative.REQUEST_DELIVER_TX, tx=b"", ) - response = self.handler.deliver_tx( - cast(AbciMessage, message), cast(AbciDialogue, dialogue) - ) + with mock.patch.object( + self.context.state.round_sequence, "add_pending_offence" + ) as mock_add_pending_offence: + response = self.handler.deliver_tx( + cast(AbciMessage, message), cast(AbciDialogue, dialogue) + ) + mock_add_pending_offence.assert_called_once() + assert response.performative == AbciMessage.Performative.RESPONSE_DELIVER_TX assert response.code == OK_CODE @@ -206,9 +216,37 @@ def test_deliver_tx_negative(self, *_: Any) -> None: performative=AbciMessage.Performative.REQUEST_DELIVER_TX, tx=b"", ) - response = self.handler.deliver_tx( - cast(AbciMessage, message), cast(AbciDialogue, dialogue) + with mock.patch.object( + self.context.state.round_sequence, "add_pending_offence" + ) as mock_add_pending_offence: + response = self.handler.deliver_tx( + cast(AbciMessage, message), cast(AbciDialogue, dialogue) + ) + mock_add_pending_offence.assert_not_called() + + assert response.performative == AbciMessage.Performative.RESPONSE_DELIVER_TX + assert response.code == ERROR_CODE + + @mock.patch.object(handlers, "Transaction") + def test_deliver_bad_tx(self, *_: Any) -> None: + """Test the 'deliver_tx' handler method, when the transaction is not ok.""" + message, dialogue = self.dialogues.create( + counterparty="", + performative=AbciMessage.Performative.REQUEST_DELIVER_TX, + tx=b"", ) + with mock.patch.object( + self.context.state.round_sequence, + "check_is_finished", + side_effect=TransactionNotValidError, + ), mock.patch.object( + self.context.state.round_sequence, "add_pending_offence" + ) as mock_add_pending_offence: + response = self.handler.deliver_tx( + cast(AbciMessage, message), cast(AbciDialogue, dialogue) + ) + mock_add_pending_offence.assert_called_once() + assert response.performative == AbciMessage.Performative.RESPONSE_DELIVER_TX assert response.code == ERROR_CODE diff --git a/packages/valory/skills/abstract_round_abci/tests/test_io/test_ipfs.py b/packages/valory/skills/abstract_round_abci/tests/test_io/test_ipfs.py index 6527d28db0..ce81b61a70 100644 --- a/packages/valory/skills/abstract_round_abci/tests/test_io/test_ipfs.py +++ b/packages/valory/skills/abstract_round_abci/tests/test_io/test_ipfs.py @@ -21,7 +21,9 @@ # pylint: skip-file -from typing import Dict, cast +import os +from pathlib import PosixPath +from typing import Any, Dict, cast from unittest import mock import pytest @@ -54,6 +56,7 @@ def test_store_and_send_and_back( multiple: bool, dummy_obj: StoredJSONType, dummy_multiple_obj: Dict[str, StoredJSONType], + tmp_path: PosixPath, ) -> None: """Test store -> send -> download -> read of objects.""" obj: StoredJSONType @@ -64,12 +67,13 @@ def test_store_and_send_and_back( obj = dummy_obj filepath = "test_file.json" + filepath = str(tmp_path / filepath) serialized_objects = self.ipfs_interact.store( filepath, obj, multiple, SupportedFiletype.JSON ) expected_objects = obj actual_objects = cast( - Dict[str, str], + Dict[str, Any], self.ipfs_interact.load( serialized_objects, SupportedFiletype.JSON, @@ -78,10 +82,7 @@ def test_store_and_send_and_back( if multiple: # here we manually remove the trailing the dir from the name. # This is done by the IPFS connection under normal circumstances. - actual_objects = { - k.lstrip(filepath).lstrip("/").lstrip("\\"): v - for k, v in actual_objects.items() - } + actual_objects = {os.path.basename(k): v for k, v in actual_objects.items()} assert actual_objects == expected_objects diff --git a/packages/valory/skills/abstract_round_abci/tests/test_models.py b/packages/valory/skills/abstract_round_abci/tests/test_models.py index 732956abe6..ee598b722e 100644 --- a/packages/valory/skills/abstract_round_abci/tests/test_models.py +++ b/packages/valory/skills/abstract_round_abci/tests/test_models.py @@ -24,13 +24,14 @@ import builtins import json import logging +import re from collections import OrderedDict from dataclasses import dataclass from enum import Enum from pathlib import Path from tempfile import TemporaryDirectory from time import sleep -from typing import Any, Dict, List, Optional, Tuple, Type, cast +from typing import Any, Dict, List, Optional, Set, Tuple, Type, cast from unittest import mock from unittest.mock import MagicMock @@ -41,6 +42,8 @@ from packages.valory.skills.abstract_round_abci.base import ( AbstractRound, BaseSynchronizedData, + OffenceStatus, + OffenseStatusEncoder, ROUND_COUNT_DEFAULT, ) from packages.valory.skills.abstract_round_abci.models import ( @@ -111,6 +114,11 @@ share_tm_config_on_startup=False, tendermint_p2p_url="", use_termination=False, + use_slashing=False, + slash_cooldown_hours=3, + slash_threshold_amount=10_000_000_000_000_000, + light_slash_unit_amount=5_000_000_000_000_000, + serious_slash_unit_amount=8_000_000_000_000_000, ) @@ -385,6 +393,78 @@ def dummy_state_setup(shared_state: SharedState) -> None: } shared_state.setup() + @pytest.mark.parametrize( + "acn_configured_agents, validator_to_agent, raises", + ( + ( + {i for i in range(4)}, + {f"validator_address_{i}": i for i in range(4)}, + False, + ), + ( + {i for i in range(5)}, + {f"validator_address_{i}": i for i in range(4)}, + True, + ), + ( + {i for i in range(4)}, + {f"validator_address_{i}": i for i in range(5)}, + True, + ), + ), + ) + def test_setup_slashing( + self, + acn_configured_agents: Set[str], + validator_to_agent: Dict[str, str], + raises: bool, + ) -> None: + """Test the `validator_to_agent` properties.""" + shared_state = SharedState(name="", skill_context=MagicMock()) + self.dummy_state_setup(shared_state) + + if not raises: + shared_state.initial_tm_configs = dict.fromkeys(acn_configured_agents) + shared_state.setup_slashing(validator_to_agent) + assert shared_state.round_sequence.validator_to_agent == validator_to_agent + + status = shared_state.round_sequence.offence_status + encoded_status = json.dumps( + status, + cls=OffenseStatusEncoder, + ) + expected_status = { + agent: OffenceStatus() for agent in acn_configured_agents + } + encoded_expected_status = json.dumps( + expected_status, cls=OffenseStatusEncoder + ) + + assert encoded_status == encoded_expected_status + + random_agent = acn_configured_agents.pop() + status[random_agent].num_unknown_offenses = 10 + assert status[random_agent].num_unknown_offenses == 10 + + for other_agent in acn_configured_agents - {random_agent}: + assert status[other_agent].num_unknown_offenses == 0 + + return + + expected_diff = acn_configured_agents.symmetric_difference( + validator_to_agent.values() + ) + with pytest.raises( + ValueError, + match=re.escape( + f"Trying to use the mapping `{validator_to_agent}`, which contains validators for non-configured " + "agents and/or does not contain validators for some configured agents. The agents which have been " + f"configured via ACN are `{acn_configured_agents}` and the diff was for {expected_diff}." + ), + ): + shared_state.initial_tm_configs = dict.fromkeys(acn_configured_agents) + shared_state.setup_slashing(validator_to_agent) + def test_setup(self, *_: Any) -> None: """Test setup method.""" shared_state = SharedState( @@ -394,6 +474,64 @@ def test_setup(self, *_: Any) -> None: self.dummy_state_setup(shared_state) assert shared_state.initial_tm_configs == {i: None for i in range(4)} + @pytest.mark.parametrize( + "initial_tm_configs, address_input, exception, expected", + ( + ( + {}, + "0x1", + "The validator address of non-participating agent `0x1` was requested.", + None, + ), + ({}, "0x0", "SharedState's setup was not performed successfully.", None), + ( + {"0x0": None}, + "0x0", + "ACN registration has not been successfully performed for agent `0x0`. " + "Have you set the `share_tm_config_on_startup` flag to `true` in the configuration?", + None, + ), + ( + {"0x0": {}}, + "0x0", + "The tendermint configuration for agent `0x0` is invalid: `{}`.", + None, + ), + ( + {"0x0": {"address": None}}, + "0x0", + "The tendermint configuration for agent `0x0` is invalid: `{'address': None}`.", + None, + ), + ( + {"0x0": {"address": "test_validator_address"}}, + "0x0", + None, + "test_validator_address", + ), + ), + ) + def test_get_validator_address( + self, + initial_tm_configs: Dict[str, Optional[Dict[str, Any]]], + address_input: str, + exception: Optional[str], + expected: Optional[str], + ) -> None: + """Test `get_validator_address` method.""" + shared_state = SharedState(name="", skill_context=MagicMock()) + with mock.patch.object(shared_state.context, "params") as mock_params: + mock_params.setup_params = { + "all_participants": ["0x0"], + } + shared_state.setup() + shared_state.initial_tm_configs = initial_tm_configs + if exception is None: + assert shared_state.get_validator_address(address_input) == expected + return + with pytest.raises(ValueError, match=exception): + shared_state.get_validator_address(address_input) + @pytest.mark.parametrize("self_idx", (range(4))) def test_acn_container(self, self_idx: int) -> None: """Test the `acn_container` method.""" @@ -432,14 +570,8 @@ def test_synchronized_data_db(self, *_: Any) -> None: "all_participants": "0x0", } shared_state.setup() - assert ( - shared_state.synchronized_data.db.get_strict("safe_contract_address") - == "0xsafe" - ) - assert ( - shared_state.synchronized_data.db.get_strict("oracle_contract_address") - == "0xoracle" - ) + for key, value in mock_params.setup_params.items(): + assert shared_state.synchronized_data.db.get_strict(key) == value @pytest.mark.parametrize( "address_to_acn_deliverable, n_participants, expected", diff --git a/packages/valory/skills/abstract_round_abci/tests/test_tools/test_rounds.py b/packages/valory/skills/abstract_round_abci/tests/test_tools/test_rounds.py index 8a3873ba57..9fbbde9ac5 100644 --- a/packages/valory/skills/abstract_round_abci/tests/test_tools/test_rounds.py +++ b/packages/valory/skills/abstract_round_abci/tests/test_tools/test_rounds.py @@ -305,6 +305,7 @@ def test_test_round(self, exit_event: DummyEvent) -> None: test_round = DummyCollectDifferentUntilAllRoundWithEndBlock( exit_event, self.base_round_test.synchronized_data, + context=MagicMock(), ) round_payloads = [ DummyTxPayload(f"agent_{i}", str(i)) for i in range(MAX_PARTICIPANTS) @@ -369,6 +370,7 @@ def test_test_round( test_round = DummyCollectSameUntilAllRoundWithEndBlock( exit_event, self.base_round_test.synchronized_data, + context=MagicMock(), ) round_payloads = { f"test{i}": DummyTxPayload(f"agent_{i}", common_value) @@ -437,6 +439,7 @@ def test_test_round(self, exit_event: DummyEvent, most_voted_payload: str) -> No test_round = DummyCollectSameUntilThresholdRoundWithEndBlock( exit_event, self.base_round_test.synchronized_data, + context=MagicMock(), ) round_payloads = { f"test{i}": DummyTxPayload(f"agent_{i}", most_voted_payload) @@ -508,6 +511,7 @@ def test_test_round(self, exit_event: DummyEvent, keeper_value: str) -> None: test_round = DummyOnlyKeeperSendsRoundTest( exit_event, self.base_round_test.synchronized_data, + context=MagicMock(), ) keeper_payload = DummyTxPayload(self.most_voted_keeper_address, keeper_value) synchronized_data_attr_checks = [ @@ -572,6 +576,7 @@ def test_test_round(self, is_keeper_set: Optional[bool]) -> None: test_round = DummyBaseVotingRoundTestWithEndBlock( self.base_round_test.synchronized_data, + context=MagicMock(), ) round_payloads = { f"test{i}": DummyTxPayload(f"agent_{i}", value="", vote=is_keeper_set) @@ -631,6 +636,7 @@ def test_test_round(self, exit_event: DummyEvent) -> None: test_round = DummyCollectDifferentUntilThresholdRoundWithEndBlock( exit_event, self.base_round_test.synchronized_data, + context=MagicMock(), ) round_payloads = { f"test{i}": DummyTxPayload(f"agent_{i}", str(i)) diff --git a/packages/valory/skills/abstract_round_abci/tests/test_utils.py b/packages/valory/skills/abstract_round_abci/tests/test_utils.py index a788839568..3f412733e8 100644 --- a/packages/valory/skills/abstract_round_abci/tests/test_utils.py +++ b/packages/valory/skills/abstract_round_abci/tests/test_utils.py @@ -31,12 +31,15 @@ from packages.valory.skills.abstract_round_abci.tests.conftest import profile_name from packages.valory.skills.abstract_round_abci.utils import ( DEFAULT_TENDERMINT_P2P_PORT, + KeyType, MAX_UINT64, + ValueType, VerifyDrand, consensus_threshold, filter_negative, get_data_from_nested_dict, get_value_with_type, + inverse, is_json_serializable, is_primitive_or_none, parse_tendermint_p2p_url, @@ -269,3 +272,36 @@ def test_filter_negative(positive: Dict[str, int], negative: Dict[str, int]) -> def test_consensus_threshold(nb: int, threshold: int) -> None: """Test `consensus_threshold`.""" assert consensus_threshold(nb) == threshold + + +@pytest.mark.parametrize( + "dict_, expected", + ( + ({}, {}), + ( + {"test": "this", "which?": "this"}, + {"this": ["test", "which?"]}, + ), + ( + {"test": "this", "which?": "this", "hm": "ok"}, + {"this": ["test", "which?"], "ok": ["hm"]}, + ), + ( + {"test": "this", "hm": "ok"}, + {"this": ["test"], "ok": ["hm"]}, + ), + ( + {"test": "this", "hm": "ok", "ok": "ok"}, + {"this": ["test"], "ok": ["hm", "ok"]}, + ), + ( + {"test": "this", "which?": "this", "hm": "ok", "ok": "ok"}, + {"this": ["test", "which?"], "ok": ["hm", "ok"]}, + ), + ), +) +def test_inverse( + dict_: Dict[KeyType, ValueType], expected: Dict[ValueType, List[KeyType]] +) -> None: + """Test `inverse`.""" + assert inverse(dict_) == expected diff --git a/packages/valory/skills/abstract_round_abci/utils.py b/packages/valory/skills/abstract_round_abci/utils.py index 790bb84f5b..864658c277 100644 --- a/packages/valory/skills/abstract_round_abci/utils.py +++ b/packages/valory/skills/abstract_round_abci/utils.py @@ -229,7 +229,7 @@ def get_args(tp): # type: ignore def is_pep604_union(ty: Type[Any]) -> bool: """Check if a type is a PEP 604 union.""" - return sys.version_info >= (3, 10) and ty is types.UnionType # type: ignore # noqa: E721 + return sys.version_info >= (3, 10) and ty is types.UnionType # type: ignore # noqa: E721 # pylint: disable=no-member def _path_to_str(path: List[str]) -> str: @@ -313,6 +313,10 @@ def check( # pylint: disable=too-many-return-statements return AutonomyTypeError(ty=ty, value=value) elif issubclass(ty, int): # For boolean return check_int(value, ty) + elif ty is typing.Any: + # `isinstance(value, typing.Any) fails on python 3.11` + # https://stackoverflow.com/questions/68031358/typeerror-typing-any-cannot-be-used-with-isinstance + pass elif not isinstance(value, ty): return AutonomyTypeError(ty=ty, value=value) return None @@ -486,3 +490,15 @@ def consensus_threshold(nb: int) -> int: :return: the consensus threshold """ return ceil((2 * nb + 1) / 3) + + +KeyType = TypeVar("KeyType") +ValueType = TypeVar("ValueType") + + +def inverse(dict_: Dict[KeyType, ValueType]) -> Dict[ValueType, List[KeyType]]: + """Get the inverse of a dictionary.""" + inverse_: Dict[ValueType, List[KeyType]] = {val: [] for val in dict_.values()} + for key, value in dict_.items(): + inverse_[value].append(key) + return inverse_ diff --git a/packages/valory/skills/counter/skill.yaml b/packages/valory/skills/counter/skill.yaml index 490d4c6f00..419b58a8c2 100644 --- a/packages/valory/skills/counter/skill.yaml +++ b/packages/valory/skills/counter/skill.yaml @@ -14,12 +14,12 @@ fingerprint: tests/test_counter.py: bafybeiazi36djqnjzu5t6rn72mngsmntoqz7z7wqa53z3lccgblgsycnbi fingerprint_ignore_patterns: [] connections: -- valory/abci:0.1.0:bafybeih2l6ssf5ebkvgbag3hx2pd22shytszqavveib2e2s6rv4va5khv4 +- valory/abci:0.1.0:bafybeih4lb2myvtypnfeji5jmgikmmazpgl3vyf5sy7oe66ji2zfjj6ily contracts: [] protocols: -- valory/abci:0.1.0:bafybeig3dj5jhsowlvg3t73kgobf6xn4nka7rkttakdb2gwsg5bp7rt7q4 +- valory/abci:0.1.0:bafybeihmzlmmb4pdo3zkhg6ehuyaa4lhw7bfpclln2o2z7v3o6fcep26iu skills: -- valory/abstract_abci:0.1.0:bafybeifuclb6cikagtg2zn7dkjnnv3f7re2tfgzk6c4h3scgyzaaqeg55m +- valory/abstract_abci:0.1.0:bafybeial6drwstqlvuizgtouc4uqgxvutwryfu7yohondemd6bd7cw3jzm behaviours: {} handlers: abci: diff --git a/packages/valory/skills/counter_client/skill.yaml b/packages/valory/skills/counter_client/skill.yaml index 5e0402a192..1cdad2cc79 100644 --- a/packages/valory/skills/counter_client/skill.yaml +++ b/packages/valory/skills/counter_client/skill.yaml @@ -18,10 +18,10 @@ fingerprint: utils.py: bafybeihrzltjkh2pfkctsuanhtx234bwcqh6vdabkxzmp7qoyva3om5x7m fingerprint_ignore_patterns: [] connections: -- valory/http_client:0.23.0:bafybeidykl4elwbcjkqn32wt5h4h7tlpeqovrcq3c5bcplt6nhpznhgczi +- valory/http_client:0.23.0:bafybeiddrfvomrmgvh5yuv2coq7ci72wcdf663stayi3m5aawnj4srggce contracts: [] protocols: -- valory/http:1.0.0:bafybeifyoio7nlh5zzyn5yz7krkou56l22to3cwg7gw5v5o3vxwklibhty +- valory/http:1.0.0:bafybeiejoqgv7finfxo3rcvvovrlj5ccrbgxodjq43uo26ylpowsa3llfe skills: [] behaviours: incrementer: diff --git a/packages/valory/skills/hello_world_abci/README.md b/packages/valory/skills/hello_world_abci/README.md deleted file mode 100644 index afd484483e..0000000000 --- a/packages/valory/skills/hello_world_abci/README.md +++ /dev/null @@ -1,34 +0,0 @@ -# Hello World abci - -## Description - -This module contains the ABCI Hello World skill for an AEA. It implements an ABCI -application for a simple demonstration. - -## Behaviours - -* `HelloWorldABCIBaseState` - - Base state behaviour for the Hello World abci skill. - -* `RegistrationBehaviour` - - Register to the next round. - -* `SelectKeeperBehaviour` - - Select the keeper agent. - -* `PrintMessageBehaviour` - - Prints the celebrated 'HELLO WORLD!' message. - -* `ResetAndPauseBehaviour` - - Reset state. - -## Handlers - -* `HelloWorldABCIHandler` -* `HttpHandler` -* `SigningHandler` diff --git a/packages/valory/skills/hello_world_abci/behaviours.py b/packages/valory/skills/hello_world_abci/behaviours.py deleted file mode 100644 index 72afb853df..0000000000 --- a/packages/valory/skills/hello_world_abci/behaviours.py +++ /dev/null @@ -1,255 +0,0 @@ -# -*- coding: utf-8 -*- -# ------------------------------------------------------------------------------ -# -# Copyright 2021-2023 Valory AG -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -# ------------------------------------------------------------------------------ - -"""This module contains the behaviours for the 'hello_world' skill.""" - -import random -from abc import ABC -from typing import Generator, Set, Type, cast - -from packages.valory.skills.abstract_round_abci.behaviours import ( - AbstractRoundBehaviour, - BaseBehaviour, -) -from packages.valory.skills.hello_world_abci.models import HelloWorldParams, SharedState -from packages.valory.skills.hello_world_abci.payloads import ( - CollectRandomnessPayload, - PrintMessagePayload, - RegistrationPayload, - ResetPayload, - SelectKeeperPayload, -) -from packages.valory.skills.hello_world_abci.rounds import ( - CollectRandomnessRound, - HelloWorldAbciApp, - PrintMessageRound, - RegistrationRound, - ResetAndPauseRound, - SelectKeeperRound, - SynchronizedData, -) - - -class HelloWorldABCIBaseBehaviour(BaseBehaviour, ABC): - """Base behaviour behaviour for the Hello World abci skill.""" - - @property - def synchronized_data(self) -> SynchronizedData: - """Return the synchronized data.""" - return cast( - SynchronizedData, cast(SharedState, self.context.state).synchronized_data - ) - - @property - def params(self) -> HelloWorldParams: - """Return the params.""" - return cast(HelloWorldParams, self.context.params) - - -class RegistrationBehaviour(HelloWorldABCIBaseBehaviour): - """Register to the next round.""" - - matching_round = RegistrationRound - - def async_act(self) -> Generator: - """ - Do the action. - - Steps: - - Build a registration transaction. - - Send the transaction and wait for it to be mined. - - Wait until ABCI application transitions to the next round. - - Go to the next behaviour (set done event). - """ - payload = RegistrationPayload(self.context.agent_address) - yield from self.send_a2a_transaction(payload) - yield from self.wait_until_round_end() - self.set_done() - - -class CollectRandomnessBehaviour(HelloWorldABCIBaseBehaviour): - """Retrieve randomness.""" - - matching_round = CollectRandomnessRound - - def async_act(self) -> Generator: - """ - Check whether tendermint is running or not. - - Steps: - - Do a http request to the tendermint health check endpoint - - Retry until healthcheck passes or timeout is hit. - - If healthcheck passes set done event. - """ - if self.context.randomness_api.is_retries_exceeded(): - # now we need to wait and see if the other agents progress the round - yield from self.wait_until_round_end() - self.set_done() - return - - api_specs = self.context.randomness_api.get_spec() - http_message, http_dialogue = self._build_http_request_message( - method=api_specs["method"], - url=api_specs["url"], - ) - response = yield from self._do_request(http_message, http_dialogue) - observation = self.context.randomness_api.process_response(response) - - if observation: - self.context.logger.info(f"Retrieved DRAND values: {observation}.") - payload = CollectRandomnessPayload( - self.context.agent_address, - observation["round"], - observation["randomness"], - ) - yield from self.send_a2a_transaction(payload) - yield from self.wait_until_round_end() - self.set_done() - else: - self.context.logger.error( - f"Could not get randomness from {self.context.randomness_api.api_id}" - ) - yield from self.sleep(self.params.sleep_time) - self.context.randomness_api.increment_retries() - - def clean_up(self) -> None: - """ - Clean up the resources due to a 'stop' event. - - It can be optionally implemented by the concrete classes. - """ - self.context.randomness_api.reset_retries() - - -class SelectKeeperBehaviour(HelloWorldABCIBaseBehaviour, ABC): - """Select the keeper agent.""" - - matching_round = SelectKeeperRound - - def async_act(self) -> Generator: - """ - Do the action. - - Steps: - - Select a keeper randomly. - - Send the transaction with the keeper and wait for it to be mined. - - Wait until ABCI application transitions to the next round. - - Go to the next behaviour (set done event). - """ - - participants = sorted(self.synchronized_data.participants) - random.seed(self.synchronized_data.most_voted_randomness, 2) # nosec - index = random.randint(0, len(participants) - 1) # nosec - - keeper_address = participants[index] - - self.context.logger.info(f"Selected a new keeper: {keeper_address}.") - payload = SelectKeeperPayload(self.context.agent_address, keeper_address) - - yield from self.send_a2a_transaction(payload) - yield from self.wait_until_round_end() - - self.set_done() - - -class PrintMessageBehaviour(HelloWorldABCIBaseBehaviour, ABC): - """Prints the celebrated 'HELLO WORLD!' message.""" - - matching_round = PrintMessageRound - - def async_act(self) -> Generator: - """ - Do the action. - - Steps: - - Determine if this agent is the current keeper agent. - - Print the appropriate to the local console. - - Send the transaction with the printed message and wait for it to be mined. - - Wait until ABCI application transitions to the next round. - - Go to the next behaviour (set done event). - """ - - if ( - self.context.agent_address - == self.synchronized_data.most_voted_keeper_address - ): - message = self.params.hello_world_string - else: - message = ":|" - - printed_message = f"Agent {self.context.agent_name} (address {self.context.agent_address}) in period {self.synchronized_data.period_count} says: {message}" - - print(printed_message) - self.context.logger.info(f"printed_message={printed_message}") - - payload = PrintMessagePayload(self.context.agent_address, printed_message) - - yield from self.send_a2a_transaction(payload) - yield from self.wait_until_round_end() - - self.set_done() - - -class ResetAndPauseBehaviour(HelloWorldABCIBaseBehaviour): - """Reset behaviour.""" - - matching_round = ResetAndPauseRound - pause = True - - def async_act(self) -> Generator: - """ - Do the action. - - Steps: - - Trivially log the behaviour. - - Sleep for configured interval. - - Build a registration transaction. - - Send the transaction and wait for it to be mined. - - Wait until ABCI application transitions to the next round. - - Go to the next behaviour (set done event). - """ - if self.pause: - self.context.logger.info("Period end.") - yield from self.sleep(self.params.reset_pause_duration) - else: - self.context.logger.info( - f"Period {self.synchronized_data.period_count} was not finished. Resetting!" - ) - - payload = ResetPayload( - self.context.agent_address, self.synchronized_data.period_count - ) - - yield from self.send_a2a_transaction(payload) - yield from self.wait_until_round_end() - self.set_done() - - -class HelloWorldRoundBehaviour(AbstractRoundBehaviour): - """This behaviour manages the consensus stages for the Hello World abci app.""" - - initial_behaviour_cls = RegistrationBehaviour - abci_app_cls = HelloWorldAbciApp - behaviours: Set[Type[BaseBehaviour]] = { - RegistrationBehaviour, # type: ignore - CollectRandomnessBehaviour, # type: ignore - SelectKeeperBehaviour, # type: ignore - PrintMessageBehaviour, # type: ignore - ResetAndPauseBehaviour, # type: ignore - } diff --git a/packages/valory/skills/hello_world_abci/fsm_specification.yaml b/packages/valory/skills/hello_world_abci/fsm_specification.yaml deleted file mode 100644 index c4da0160b4..0000000000 --- a/packages/valory/skills/hello_world_abci/fsm_specification.yaml +++ /dev/null @@ -1,29 +0,0 @@ -alphabet_in: -- DONE -- NO_MAJORITY -- RESET_TIMEOUT -- ROUND_TIMEOUT -default_start_state: RegistrationRound -final_states: [] -label: HelloWorldAbciApp -start_states: -- RegistrationRound -states: -- CollectRandomnessRound -- PrintMessageRound -- RegistrationRound -- ResetAndPauseRound -- SelectKeeperRound -transition_func: - (CollectRandomnessRound, DONE): SelectKeeperRound - (CollectRandomnessRound, NO_MAJORITY): CollectRandomnessRound - (CollectRandomnessRound, ROUND_TIMEOUT): CollectRandomnessRound - (PrintMessageRound, DONE): ResetAndPauseRound - (PrintMessageRound, ROUND_TIMEOUT): RegistrationRound - (RegistrationRound, DONE): CollectRandomnessRound - (ResetAndPauseRound, DONE): CollectRandomnessRound - (ResetAndPauseRound, NO_MAJORITY): RegistrationRound - (ResetAndPauseRound, RESET_TIMEOUT): RegistrationRound - (SelectKeeperRound, DONE): PrintMessageRound - (SelectKeeperRound, NO_MAJORITY): RegistrationRound - (SelectKeeperRound, ROUND_TIMEOUT): RegistrationRound diff --git a/packages/valory/skills/hello_world_abci/rounds.py b/packages/valory/skills/hello_world_abci/rounds.py deleted file mode 100644 index 7439c7ba2b..0000000000 --- a/packages/valory/skills/hello_world_abci/rounds.py +++ /dev/null @@ -1,224 +0,0 @@ -# -*- coding: utf-8 -*- -# ------------------------------------------------------------------------------ -# -# Copyright 2021-2023 Valory AG -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -# ------------------------------------------------------------------------------ -"""This module contains the data classes for the Hello World ABCI application.""" - -from abc import ABC -from enum import Enum -from typing import Dict, List, Optional, Tuple, Type, cast - -from packages.valory.skills.abstract_round_abci.base import ( - AbciApp, - AbciAppTransitionFunction, - AbstractRound, - AppState, - BaseSynchronizedData, - CollectDifferentUntilAllRound, - CollectSameUntilAllRound, - CollectSameUntilThresholdRound, - get_name, -) -from packages.valory.skills.hello_world_abci.payloads import ( - CollectRandomnessPayload, - PrintMessagePayload, - RegistrationPayload, - ResetPayload, - SelectKeeperPayload, -) - - -class Event(Enum): - """Event enumeration for the Hello World ABCI demo.""" - - DONE = "done" - ROUND_TIMEOUT = "round_timeout" - NO_MAJORITY = "no_majority" - RESET_TIMEOUT = "reset_timeout" - - -class SynchronizedData( - BaseSynchronizedData -): # pylint: disable=too-many-instance-attributes - """ - Class to represent the synchronized data. - - This state is replicated by the Tendermint application. - """ - - @property - def printed_messages(self) -> List[str]: - """Get the printed messages list.""" - - return cast( - List[str], - self.db.get_strict("printed_messages"), - ) - - -class HelloWorldABCIAbstractRound(AbstractRound, ABC): - """Abstract round for the Hello World ABCI skill.""" - - synchronized_data_class: Type[BaseSynchronizedData] = SynchronizedData - - @property - def synchronized_data(self) -> SynchronizedData: - """Return the synchronized data.""" - return cast(SynchronizedData, self._synchronized_data) - - -class RegistrationRound(CollectSameUntilAllRound, HelloWorldABCIAbstractRound): - """A round in which the agents get registered""" - - payload_class = RegistrationPayload - - def end_block(self) -> Optional[Tuple[BaseSynchronizedData, Event]]: - """Process the end of the block.""" - - if self.collection_threshold_reached: - synchronized_data = self.synchronized_data.update( - participants=tuple(sorted(self.collection)), - synchronized_data_class=SynchronizedData, - ) - return synchronized_data, Event.DONE - return None - - -class CollectRandomnessRound( - CollectSameUntilThresholdRound, HelloWorldABCIAbstractRound -): - """A round for collecting randomness""" - - payload_class = CollectRandomnessPayload - synchronized_data_class = SynchronizedData - done_event = Event.DONE - no_majority_event = Event.NO_MAJORITY - collection_key = get_name(SynchronizedData.participant_to_randomness) - selection_key = get_name(SynchronizedData.most_voted_randomness) - - -class SelectKeeperRound(CollectSameUntilThresholdRound, HelloWorldABCIAbstractRound): - """A round in a which keeper is selected""" - - payload_class = SelectKeeperPayload - synchronized_data_class = SynchronizedData - done_event = Event.DONE - no_majority_event = Event.NO_MAJORITY - collection_key = get_name(SynchronizedData.participant_to_selection) - selection_key = get_name(SynchronizedData.most_voted_keeper_address) - - -class PrintMessageRound(CollectDifferentUntilAllRound, HelloWorldABCIAbstractRound): - """A round in which the keeper prints the message""" - - payload_class = PrintMessagePayload - - def end_block(self) -> Optional[Tuple[BaseSynchronizedData, Event]]: - """Process the end of the block.""" - if self.collection_threshold_reached: - synchronized_data = self.synchronized_data.update( - participants=tuple(sorted(self.collection)), - printed_messages=sorted( - [ - cast(PrintMessagePayload, payload).message - for payload in self.collection.values() - ] - ), - synchronized_data_class=SynchronizedData, - ) - return synchronized_data, Event.DONE - return None - - -class ResetAndPauseRound(CollectSameUntilThresholdRound, HelloWorldABCIAbstractRound): - """This class represents the base reset round.""" - - payload_class = ResetPayload - - def end_block(self) -> Optional[Tuple[BaseSynchronizedData, Event]]: - """Process the end of the block.""" - if self.threshold_reached: - return self.synchronized_data.create(), Event.DONE - if not self.is_majority_possible( - self.collection, self.synchronized_data.nb_participants - ): - return self.synchronized_data, Event.NO_MAJORITY - return None - - -class HelloWorldAbciApp(AbciApp[Event]): - """HelloWorldAbciApp - - Initial round: RegistrationRound - - Initial states: {RegistrationRound} - - Transition states: - 0. RegistrationRound - - done: 1. - 1. CollectRandomnessRound - - done: 2. - - no majority: 1. - - round timeout: 1. - 2. SelectKeeperRound - - done: 3. - - no majority: 0. - - round timeout: 0. - 3. PrintMessageRound - - done: 4. - - round timeout: 0. - 4. ResetAndPauseRound - - done: 1. - - no majority: 0. - - reset timeout: 0. - - Final states: {} - - Timeouts: - round timeout: 30.0 - reset timeout: 30.0 - """ - - initial_round_cls: AppState = RegistrationRound - transition_function: AbciAppTransitionFunction = { - RegistrationRound: { - Event.DONE: CollectRandomnessRound, - }, - CollectRandomnessRound: { - Event.DONE: SelectKeeperRound, - Event.NO_MAJORITY: CollectRandomnessRound, - Event.ROUND_TIMEOUT: CollectRandomnessRound, - }, - SelectKeeperRound: { - Event.DONE: PrintMessageRound, - Event.NO_MAJORITY: RegistrationRound, - Event.ROUND_TIMEOUT: RegistrationRound, - }, - PrintMessageRound: { - Event.DONE: ResetAndPauseRound, - Event.ROUND_TIMEOUT: RegistrationRound, - }, - ResetAndPauseRound: { - Event.DONE: CollectRandomnessRound, - Event.NO_MAJORITY: RegistrationRound, - Event.RESET_TIMEOUT: RegistrationRound, - }, - } - event_to_timeout: Dict[Event, float] = { - Event.ROUND_TIMEOUT: 30.0, - Event.RESET_TIMEOUT: 30.0, - } diff --git a/packages/valory/skills/hello_world_abci/tests/test_behaviours.py b/packages/valory/skills/hello_world_abci/tests/test_behaviours.py deleted file mode 100644 index 6def86245d..0000000000 --- a/packages/valory/skills/hello_world_abci/tests/test_behaviours.py +++ /dev/null @@ -1,417 +0,0 @@ -# -*- coding: utf-8 -*- -# ------------------------------------------------------------------------------ -# -# Copyright 2021-2023 Valory AG -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -# ------------------------------------------------------------------------------ - -"""Tests for valory/hello_world_abci skill's behaviours.""" - -# pylint: skip-file - -import json -import time -from pathlib import Path -from typing import Any, Type, cast -from unittest import mock - -from aea.skills.base import SkillContext - -from packages.valory.skills.abstract_round_abci.base import AbciAppDB -from packages.valory.skills.abstract_round_abci.behaviour_utils import BaseBehaviour -from packages.valory.skills.abstract_round_abci.test_tools.base import ( - FSMBehaviourBaseCase, -) -from packages.valory.skills.hello_world_abci import PUBLIC_ID -from packages.valory.skills.hello_world_abci.behaviours import ( - CollectRandomnessBehaviour, - PrintMessageBehaviour, - RegistrationBehaviour, - ResetAndPauseBehaviour, - SelectKeeperBehaviour, -) -from packages.valory.skills.hello_world_abci.rounds import Event, SynchronizedData - - -PACKAGE_DIR = Path(__file__).parent.parent - - -def test_skill_public_id() -> None: - """Test skill module public ID""" - - assert PUBLIC_ID.name == Path(__file__).parents[1].name - assert PUBLIC_ID.author == Path(__file__).parents[3].name - - -class HelloWorldAbciFSMBehaviourBaseCase(FSMBehaviourBaseCase): - """Base case for testing PriceEstimation FSMBehaviour.""" - - path_to_skill = PACKAGE_DIR - - def setup(self, **kwargs: Any) -> None: - """ - Set up the test method. - - Called each time before a test method is called. - - :param kwargs: the keyword arguments passed to _prepare_skill - """ - super().setup(**kwargs) - self.synchronized_data = SynchronizedData( - AbciAppDB( - setup_data=dict( - most_voted_keeper_address=["most_voted_keeper_address"], - ), - ) - ) - - def end_round( # type: ignore - self, - ) -> None: - """Ends round early to cover `wait_for_end` generator.""" - super().end_round(Event.DONE) - - -class BaseCollectRandomnessBehaviourTest(HelloWorldAbciFSMBehaviourBaseCase): - """Test CollectRandomnessBehaviour.""" - - collect_randomness_behaviour_class: Type[BaseBehaviour] - next_behaviour_class: Type[BaseBehaviour] - - def test_randomness_behaviour( - self, - ) -> None: - """Test RandomnessBehaviour.""" - - self.fast_forward_to_behaviour( - self.behaviour, - self.collect_randomness_behaviour_class.auto_behaviour_id(), - self.synchronized_data, - ) - assert ( - cast( - BaseBehaviour, - cast(BaseBehaviour, self.behaviour.current_behaviour), - ).behaviour_id - == self.collect_randomness_behaviour_class.auto_behaviour_id() - ) - self.behaviour.act_wrapper() - self.mock_http_request( - request_kwargs=dict( - method="GET", - headers="", - version="", - body=b"", - url="https://drand.cloudflare.com/public/latest", - ), - response_kwargs=dict( - version="", - status_code=200, - status_text="", - headers="", - body=json.dumps( - { - "round": 1283255, - "randomness": "04d4866c26e03347d2431caa82ab2d7b7bdbec8b58bca9460c96f5265d878feb", - } - ).encode("utf-8"), - ), - ) - - self.behaviour.act_wrapper() - self.mock_a2a_transaction() - self._test_done_flag_set() - self.end_round() - - behaviour = cast(BaseBehaviour, self.behaviour.current_behaviour) - assert behaviour.behaviour_id == self.next_behaviour_class.auto_behaviour_id() - - def test_invalid_response( - self, - ) -> None: - """Test invalid json response.""" - self.fast_forward_to_behaviour( - self.behaviour, - self.collect_randomness_behaviour_class.auto_behaviour_id(), - self.synchronized_data, - ) - assert ( - cast( - BaseBehaviour, - cast(BaseBehaviour, self.behaviour.current_behaviour), - ).behaviour_id - == self.collect_randomness_behaviour_class.auto_behaviour_id() - ) - self.behaviour.act_wrapper() - - self.mock_http_request( - request_kwargs=dict( - method="GET", - headers="", - version="", - body=b"", - url="https://drand.cloudflare.com/public/latest", - ), - response_kwargs=dict( - version="", status_code=200, status_text="", headers="", body=b"" - ), - ) - self.behaviour.act_wrapper() - time.sleep(1) - self.behaviour.act_wrapper() - - def test_max_retries_reached( - self, - ) -> None: - """Test with max retries reached.""" - self.fast_forward_to_behaviour( - self.behaviour, - self.collect_randomness_behaviour_class.auto_behaviour_id(), - self.synchronized_data, - ) - assert ( - cast( - BaseBehaviour, - cast(BaseBehaviour, self.behaviour.current_behaviour), - ).behaviour_id - == self.collect_randomness_behaviour_class.auto_behaviour_id() - ) - self.behaviour.context.randomness_api.__dict__["_frozen"] = False - with mock.patch.object( - self.behaviour.context.randomness_api, - "is_retries_exceeded", - return_value=True, - ): - self.behaviour.act_wrapper() - behaviour = cast(BaseBehaviour, self.behaviour.current_behaviour) - assert ( - behaviour.behaviour_id - == self.collect_randomness_behaviour_class.auto_behaviour_id() - ) - self._test_done_flag_set() - self.behaviour.context.randomness_api.__dict__["_frozen"] = True - - def test_clean_up( - self, - ) -> None: - """Test when `observed` value is none.""" - self.fast_forward_to_behaviour( - self.behaviour, - self.collect_randomness_behaviour_class.auto_behaviour_id(), - self.synchronized_data, - ) - assert ( - cast( - BaseBehaviour, - cast(BaseBehaviour, self.behaviour.current_behaviour), - ).behaviour_id - == self.collect_randomness_behaviour_class.auto_behaviour_id() - ) - self.behaviour.context.randomness_api.retries_info.retries_attempted = 1 - assert self.behaviour.current_behaviour is not None - self.behaviour.current_behaviour.clean_up() - assert self.behaviour.context.randomness_api.retries_info.retries_attempted == 0 - - -class BaseSelectKeeperBehaviourTest(HelloWorldAbciFSMBehaviourBaseCase): - """Test SelectKeeperBehaviour.""" - - select_keeper_behaviour_class: Type[BaseBehaviour] - next_behaviour_class: Type[BaseBehaviour] - - def test_select_keeper( - self, - ) -> None: - """Test select keeper agent.""" - participants = (self.skill.skill_context.agent_address, "a_1", "a_2") - self.fast_forward_to_behaviour( - behaviour=self.behaviour, - behaviour_id=self.select_keeper_behaviour_class.auto_behaviour_id(), - synchronized_data=SynchronizedData( - AbciAppDB( - setup_data=dict( - participants=[participants], - most_voted_randomness=[ - "56cbde9e9bbcbdcaf92f183c678eaa5288581f06b1c9c7f884ce911776727688" - ], - most_voted_keeper_address=["most_voted_keeper_address"], - ), - ) - ), - ) - assert ( - cast( - BaseBehaviour, - cast(BaseBehaviour, self.behaviour.current_behaviour), - ).behaviour_id - == self.select_keeper_behaviour_class.auto_behaviour_id() - ) - self.behaviour.act_wrapper() - self.mock_a2a_transaction() - self._test_done_flag_set() - self.end_round() - behaviour = cast(BaseBehaviour, self.behaviour.current_behaviour) - assert behaviour.behaviour_id == self.next_behaviour_class.auto_behaviour_id() - - -class TestRegistrationBehaviour(HelloWorldAbciFSMBehaviourBaseCase): - """Test case to test RegistrationBehaviour.""" - - def test_registration(self) -> None: - """Test registration.""" - self.fast_forward_to_behaviour( - self.behaviour, - RegistrationBehaviour.auto_behaviour_id(), - self.synchronized_data, - ) - assert ( - cast( - BaseBehaviour, - cast(BaseBehaviour, self.behaviour.current_behaviour), - ).behaviour_id - == RegistrationBehaviour.auto_behaviour_id() - ) - self.behaviour.act_wrapper() - self.mock_a2a_transaction() - self._test_done_flag_set() - - self.end_round() - behaviour = cast(BaseBehaviour, self.behaviour.current_behaviour) - assert behaviour.behaviour_id == CollectRandomnessBehaviour.auto_behaviour_id() - - -class TestCollectRandomnessBehaviour(BaseCollectRandomnessBehaviourTest): - """Test CollectRandomnessBehaviour.""" - - collect_randomness_behaviour_class = CollectRandomnessBehaviour - next_behaviour_class = SelectKeeperBehaviour - - -class TestSelectKeeperBehaviour(BaseSelectKeeperBehaviourTest): - """Test SelectKeeperBehaviour.""" - - select_keeper_behaviour_class = SelectKeeperBehaviour - next_behaviour_class = PrintMessageBehaviour - - -class TestPrintMessageBehaviour(HelloWorldAbciFSMBehaviourBaseCase): - """Test case to test PrintMessageBehaviour.""" - - def test_print_message_non_keeper(self) -> None: - """Test print_message.""" - self.fast_forward_to_behaviour( - self.behaviour, - PrintMessageBehaviour.auto_behaviour_id(), - self.synchronized_data, - ) - assert ( - cast( - BaseBehaviour, - cast(BaseBehaviour, self.behaviour.current_behaviour), - ).behaviour_id - == PrintMessageBehaviour.auto_behaviour_id() - ) - self.behaviour.act_wrapper() - self.mock_a2a_transaction() - self._test_done_flag_set() - - self.end_round() - behaviour = cast(BaseBehaviour, self.behaviour.current_behaviour) - assert behaviour.behaviour_id == ResetAndPauseBehaviour.auto_behaviour_id() - - @mock.patch.object(SkillContext, "agent_address", new_callable=mock.PropertyMock) - def test_print_message_keeper( - self, - agent_address_mock: mock.PropertyMock, - ) -> None: - """Test print_message.""" - agent_address_mock.return_value = "most_voted_keeper_address" - self.fast_forward_to_behaviour( - self.behaviour, - PrintMessageBehaviour.auto_behaviour_id(), - self.synchronized_data, - ) - assert ( - cast( - BaseBehaviour, - cast(BaseBehaviour, self.behaviour.current_behaviour), - ).behaviour_id - == PrintMessageBehaviour.auto_behaviour_id() - ) - self.behaviour.act_wrapper() - self.mock_a2a_transaction() - self._test_done_flag_set() - - self.end_round() - behaviour = cast(BaseBehaviour, self.behaviour.current_behaviour) - assert behaviour.behaviour_id == ResetAndPauseBehaviour.auto_behaviour_id() - - -class TestResetAndPauseBehaviour(HelloWorldAbciFSMBehaviourBaseCase): - """Test ResetBehaviour.""" - - behaviour_class = ResetAndPauseBehaviour - next_behaviour_class = CollectRandomnessBehaviour - - def test_pause_and_reset_behaviour( - self, - ) -> None: - """Test pause and reset behaviour.""" - self.fast_forward_to_behaviour( - behaviour=self.behaviour, - behaviour_id=self.behaviour_class.auto_behaviour_id(), - synchronized_data=self.synchronized_data, - ) - assert ( - cast( - BaseBehaviour, - cast(BaseBehaviour, self.behaviour.current_behaviour), - ).behaviour_id - == self.behaviour_class.auto_behaviour_id() - ) - self.behaviour.context.params.__dict__["reset_pause_duration"] = 0.1 - self.behaviour.act_wrapper() - time.sleep(0.3) - self.behaviour.act_wrapper() - self.mock_a2a_transaction() - self._test_done_flag_set() - self.end_round() - behaviour = cast(BaseBehaviour, self.behaviour.current_behaviour) - assert behaviour.behaviour_id == self.next_behaviour_class.auto_behaviour_id() - - def test_reset_behaviour( - self, - ) -> None: - """Test reset behaviour.""" - self.fast_forward_to_behaviour( - behaviour=self.behaviour, - behaviour_id=self.behaviour_class.auto_behaviour_id(), - synchronized_data=self.synchronized_data, - ) - assert self.behaviour.current_behaviour is not None - self.behaviour.current_behaviour.pause = False - assert ( - cast( - BaseBehaviour, - cast(BaseBehaviour, self.behaviour.current_behaviour), - ).behaviour_id - == self.behaviour_class.auto_behaviour_id() - ) - self.behaviour.act_wrapper() - self.mock_a2a_transaction() - self._test_done_flag_set() - self.end_round() - behaviour = cast(BaseBehaviour, self.behaviour.current_behaviour) - assert behaviour.behaviour_id == self.next_behaviour_class.auto_behaviour_id() diff --git a/packages/valory/skills/hello_world_abci/tests/test_payloads.py b/packages/valory/skills/hello_world_abci/tests/test_payloads.py deleted file mode 100644 index 7e3855026f..0000000000 --- a/packages/valory/skills/hello_world_abci/tests/test_payloads.py +++ /dev/null @@ -1,78 +0,0 @@ -# -*- coding: utf-8 -*- -# ------------------------------------------------------------------------------ -# -# Copyright 2021-2023 Valory AG -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -# ------------------------------------------------------------------------------ - -"""Test the payloads.py module of the skill.""" - -# pylint: skip-file - -from packages.valory.skills.hello_world_abci.payloads import ( - CollectRandomnessPayload, - PrintMessagePayload, - RegistrationPayload, - ResetPayload, - SelectKeeperPayload, -) - - -def test_registration_payload() -> None: - """Test `RegistrationPayload`.""" - - payload = RegistrationPayload(sender="sender") - - assert payload.sender == "sender" - - -def test_collect_randomness_payload() -> None: - """Test `CollectRandomnessPayload`""" - - payload = CollectRandomnessPayload(sender="sender", round_id=1, randomness="1") - - assert payload.round_id == 1 - assert payload.randomness == "1" - assert payload.id_ - assert payload.data == {"round_id": 1, "randomness": "1"} - - -def test_select_keeper_payload() -> None: - """Test `SelectKeeperPayload`.""" - - payload = SelectKeeperPayload(sender="sender", keeper="keeper") - - assert payload.keeper == "keeper" - assert payload.data == {"keeper": "keeper"} - - -def test_print_message_payload() -> None: - """Test `PrintMessagePayload`.""" - - payload = PrintMessagePayload(sender="sender", message="message") - - assert payload.message == "message" - assert payload.data == {"message": "message"} - - -def test_reset_payload() -> None: - """Test `ResetPayload`""" - - payload = ResetPayload(sender="sender", period_count=1) - - assert payload.period_count == 1 - assert payload.id_ - assert payload.data == {"period_count": 1} - assert hash(payload) diff --git a/packages/valory/skills/hello_world_abci/tests/test_rounds.py b/packages/valory/skills/hello_world_abci/tests/test_rounds.py deleted file mode 100644 index 4f813e68d2..0000000000 --- a/packages/valory/skills/hello_world_abci/tests/test_rounds.py +++ /dev/null @@ -1,334 +0,0 @@ -# -*- coding: utf-8 -*- -# ------------------------------------------------------------------------------ -# -# Copyright 2021-2023 Valory AG -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -# ------------------------------------------------------------------------------ - -"""Test the rounds of the skill.""" - -# pylint: skip-file - -import logging # noqa: F401 -from typing import cast - -from packages.valory.skills.abstract_round_abci.base import ( - AbciAppDB, - CollectionRound, - MAX_INT_256, -) -from packages.valory.skills.abstract_round_abci.test_tools.rounds import ( - BaseRoundTestClass as ExternalBaseRoundTestClass, -) -from packages.valory.skills.hello_world_abci.payloads import ( - CollectRandomnessPayload, - PrintMessagePayload, - RegistrationPayload, - ResetPayload, - SelectKeeperPayload, -) -from packages.valory.skills.hello_world_abci.rounds import ( - CollectRandomnessRound, - Event, - PrintMessageRound, - RegistrationRound, - ResetAndPauseRound, - SelectKeeperRound, - SynchronizedData, -) - - -MAX_PARTICIPANTS: int = 4 -RANDOMNESS: str = "d1c29dce46f979f9748210d24bce4eae8be91272f5ca1a6aea2832d3dd676f51" - - -class BaseRoundTestClass(ExternalBaseRoundTestClass): - """Base test class for Rounds.""" - - _synchronized_data_class = SynchronizedData - _event_class = Event - - -class TestRegistrationRound(BaseRoundTestClass): - """Tests for RegistrationRound.""" - - def test_run( - self, - ) -> None: - """Run tests.""" - - test_round = RegistrationRound( - synchronized_data=self.synchronized_data, - ) - - first_payload, *payloads = [ - RegistrationPayload(sender=participant) for participant in self.participants - ] - - test_round.process_payload(first_payload) - assert test_round.collection == {first_payload.sender: first_payload} - assert test_round.end_block() is None - - for payload in payloads: - test_round.process_payload(payload) - - actual_next_behaviour = SynchronizedData( - AbciAppDB(setup_data=dict(participants=[tuple(test_round.collection)])) - ) - - res = test_round.end_block() - assert res is not None - synchronized_data, event = res - assert ( - cast(SynchronizedData, synchronized_data).participants - == cast(SynchronizedData, actual_next_behaviour).participants - ) - assert event == Event.DONE - - -class TestCollectRandomnessRound(BaseRoundTestClass): - """Tests for CollectRandomnessRound.""" - - def test_run( - self, - ) -> None: - """Run tests.""" - - test_round = CollectRandomnessRound( - synchronized_data=self.synchronized_data, - ) - first_payload, *payloads = [ - CollectRandomnessPayload( - sender=participant, randomness=RANDOMNESS, round_id=0 - ) - for participant in self.participants - ] - - test_round.process_payload(first_payload) - assert test_round.collection[first_payload.sender] == first_payload - assert test_round.end_block() is None - - self._test_no_majority_event(test_round) - - for payload in payloads: - test_round.process_payload(payload) - - actual_next_behaviour = self.synchronized_data.update( - participant_to_randomness=test_round.serialized_collection, - most_voted_randomness=test_round.most_voted_payload, - ) - - res = test_round.end_block() - assert res is not None - synchronized_data, event = res - assert all( - [ - key - in cast(SynchronizedData, synchronized_data).participant_to_randomness - for key in cast( - SynchronizedData, actual_next_behaviour - ).participant_to_randomness - ] - ) - assert event == Event.DONE - - -class TestSelectKeeperRound(BaseRoundTestClass): - """Tests for SelectKeeperRound.""" - - def test_run( - self, - ) -> None: - """Run tests.""" - - test_round = SelectKeeperRound( - synchronized_data=self.synchronized_data, - ) - - first_payload, *payloads = [ - SelectKeeperPayload(sender=participant, keeper="keeper") - for participant in self.participants - ] - - test_round.process_payload(first_payload) - assert test_round.collection[first_payload.sender] == first_payload - assert test_round.end_block() is None - - self._test_no_majority_event(test_round) - - for payload in payloads: - test_round.process_payload(payload) - - actual_next_behaviour = self.synchronized_data.update( - participant_to_selection=test_round.serialized_collection, - most_voted_keeper_address=test_round.most_voted_payload, - ) - - res = test_round.end_block() - assert res is not None - synchronized_data, event = res - assert all( - [ - key - in cast(SynchronizedData, synchronized_data).participant_to_selection - for key in cast( - SynchronizedData, actual_next_behaviour - ).participant_to_selection - ] - ) - assert event == Event.DONE - - -class TestPrintMessageRound(BaseRoundTestClass): - """Tests for PrintMessageRound.""" - - def test_run( - self, - ) -> None: - """Run tests.""" - - test_round = PrintMessageRound( - synchronized_data=self.synchronized_data, - ) - - first_payload, *payloads = [ - PrintMessagePayload(sender=participant, message=f"{participant}_message") - for participant in self.participants - ] - - test_round.process_payload(first_payload) - assert test_round.collection == {first_payload.sender: first_payload} - assert test_round.end_block() is None - - for payload in payloads: - test_round.process_payload(payload) - - printed_messages = [ - cast(PrintMessagePayload, payload).message - for payload in test_round.collection.values() - ] - - actual_next_behaviour = SynchronizedData( - AbciAppDB( - setup_data=dict( - participants=[tuple(sorted(test_round.collection))], - printed_messages=[sorted(printed_messages)], - ) - ) - ) - - res = test_round.end_block() - assert res is not None - synchronized_data, event = res - - assert ( - cast(SynchronizedData, synchronized_data).participants - == cast(SynchronizedData, actual_next_behaviour).participants - ) - assert ( - cast(SynchronizedData, synchronized_data).printed_messages - == cast(SynchronizedData, actual_next_behaviour).printed_messages - ) - assert event == Event.DONE - - -class TestResetAndPauseRound(BaseRoundTestClass): - """Tests for ResetAndPauseRound.""" - - def test_run( - self, - ) -> None: - """Run tests.""" - test_round = ResetAndPauseRound( - synchronized_data=self.synchronized_data, - ) - - first_payload, *payloads = [ - ResetPayload(sender=participant, period_count=1) - for participant in self.participants - ] - - test_round.process_payload(first_payload) - assert test_round.collection[first_payload.sender] == first_payload - assert test_round.end_block() is None - - self._test_no_majority_event(test_round) - - for payload in payloads: - test_round.process_payload(payload) - - actual_next_behaviour = self.synchronized_data.create() - - res = test_round.end_block() - assert res is not None - synchronized_data, event = res - - assert ( - cast(SynchronizedData, synchronized_data).period_count - == cast(SynchronizedData, actual_next_behaviour).period_count - ) - - assert event == Event.DONE - - -def test_synchronized_data() -> None: # pylint:too-many-locals - """Test SynchronizedData.""" - - participants = tuple(f"agent_{i}" for i in range(MAX_PARTICIPANTS)) - participant_to_randomness = { - participant: CollectRandomnessPayload( - sender=participant, randomness=RANDOMNESS, round_id=0 - ) - for participant in participants - } - participant_to_randomness_serialized = CollectionRound.serialize_collection( - participant_to_randomness - ) - most_voted_randomness = "0xabcd" - participant_to_selection = { - participant: SelectKeeperPayload(sender=participant, keeper="keeper") - for participant in participants - } - participant_to_selection_serialized = CollectionRound.serialize_collection( - participant_to_selection - ) - most_voted_keeper_address = "keeper" - - synchronized_data = SynchronizedData( - AbciAppDB( - setup_data=AbciAppDB.data_to_lists( - dict( - participants=participants, - setup_params={}, - participant_to_randomness=participant_to_randomness_serialized, - most_voted_randomness=most_voted_randomness, - participant_to_selection=participant_to_selection_serialized, - most_voted_keeper_address=most_voted_keeper_address, - ) - ), - ) - ) - - assert synchronized_data.participants == frozenset(participants) - assert synchronized_data.period_count == 0 - assert synchronized_data.participant_to_randomness == participant_to_randomness - assert synchronized_data.most_voted_randomness == most_voted_randomness - assert synchronized_data.participant_to_selection == participant_to_selection - assert synchronized_data.most_voted_keeper_address == most_voted_keeper_address - assert synchronized_data.sorted_participants == sorted(participants) - actual_keeper_randomness = int(most_voted_randomness, base=16) / MAX_INT_256 - assert ( - abs(synchronized_data.keeper_randomness - actual_keeper_randomness) < 1e-10 - ) # avoid equality comparisons between floats diff --git a/packages/valory/skills/offend_abci/README.md b/packages/valory/skills/offend_abci/README.md new file mode 100644 index 0000000000..adf0a503d5 --- /dev/null +++ b/packages/valory/skills/offend_abci/README.md @@ -0,0 +1,7 @@ +# Offend ABCI + +## Description + +This module contains a skill that creates offences. + +Its purpose is to facilitate testing of the slashing implementation. diff --git a/packages/valory/skills/hello_world_abci/__init__.py b/packages/valory/skills/offend_abci/__init__.py similarity index 78% rename from packages/valory/skills/hello_world_abci/__init__.py rename to packages/valory/skills/offend_abci/__init__.py index 7522845e5b..66ed1c108c 100644 --- a/packages/valory/skills/hello_world_abci/__init__.py +++ b/packages/valory/skills/offend_abci/__init__.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- # ------------------------------------------------------------------------------ # -# Copyright 2021-2022 Valory AG +# Copyright 2023 Valory AG # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -18,12 +18,12 @@ # ------------------------------------------------------------------------------ """ -This module contains the ABCI Hello World skill for an AEA. +This module contains a skill that creates offences. -It implements an ABCI application for a Hello World! demonstration. +Its purpose is to facilitate testing of the slashing implementation. """ from aea.configurations.base import PublicId -PUBLIC_ID = PublicId.from_str("valory/hello_world_abci:0.1.0") +PUBLIC_ID = PublicId.from_str("valory/offend_abci:0.1.0") diff --git a/packages/valory/skills/offend_abci/behaviours.py b/packages/valory/skills/offend_abci/behaviours.py new file mode 100644 index 0000000000..280a7df6f5 --- /dev/null +++ b/packages/valory/skills/offend_abci/behaviours.py @@ -0,0 +1,109 @@ +# -*- coding: utf-8 -*- +# ------------------------------------------------------------------------------ +# +# Copyright 2023 Valory AG +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# ------------------------------------------------------------------------------ + +"""This module contains the behaviours for the 'offend_abci' skill.""" + +import json +from copy import deepcopy +from typing import Dict, Generator, Set, Type, cast + +from packages.valory.skills.abstract_round_abci.base import ( + NUMBER_OF_BLOCKS_TRACKED, + NUMBER_OF_ROUNDS_TRACKED, + OffenceStatus, + OffenseStatusEncoder, +) +from packages.valory.skills.abstract_round_abci.behaviours import ( + AbstractRoundBehaviour, + BaseBehaviour, +) +from packages.valory.skills.offend_abci.models import OffendParams, SharedState +from packages.valory.skills.offend_abci.payloads import OffencesPayload +from packages.valory.skills.offend_abci.rounds import OffendAbciApp, OffendRound + + +class OffendBehaviour(BaseBehaviour): + """Simulate offences.""" + + matching_round = OffendRound + + @property + def shared_state(self) -> SharedState: + """Get the round sequence from the shared state.""" + return cast(SharedState, self.context.state) + + @property + def offence_status(self) -> Dict[str, OffenceStatus]: + """Get the offence status from the round sequence.""" + return self.shared_state.round_sequence.offence_status + + @property + def first_agent(self) -> str: + """Short the agents' addresses and get the first address.""" + return sorted(self.shared_state.synchronized_data.all_participants)[0] + + @property + def params(self) -> OffendParams: + """Return the params.""" + return cast(OffendParams, self.context.params) + + def _updated_status(self) -> Dict[str, OffenceStatus]: + """Return the offense status updated.""" + status_per_agent = deepcopy(self.offence_status) + affected_agent = self.first_agent + status = status_per_agent[affected_agent] + + if self.params.validator_downtime: + for _ in range(NUMBER_OF_BLOCKS_TRACKED): + status.validator_downtime.add(True) + + for _ in range(NUMBER_OF_ROUNDS_TRACKED): + if self.params.invalid_payload: + status.invalid_payload.add(True) + if self.params.blacklisted: + status.blacklisted.add(True) + if self.params.suspected: + status.suspected.add(True) + + status.num_unknown_offenses = self.params.num_unknown + status.num_double_signed = self.params.num_double_signed + status.num_light_client_attack = self.params.num_light_client_attack + + return status_per_agent + + def async_act(self) -> Generator: + """Create offences.""" + updated_status = self._updated_status() + serialized_status = json.dumps( + updated_status, cls=OffenseStatusEncoder, sort_keys=True + ) + payload = OffencesPayload(self.context.agent_address, serialized_status) + yield from self.send_a2a_transaction(payload) + yield from self.wait_until_round_end() + self.set_done() + + +class OffendRoundBehaviour(AbstractRoundBehaviour): + """This behaviour manages the consensus stages for the Offend abci app.""" + + initial_behaviour_cls = OffendBehaviour + abci_app_cls = OffendAbciApp + behaviours: Set[Type[BaseBehaviour]] = { + OffendBehaviour, # type: ignore + } diff --git a/packages/valory/skills/hello_world_abci/dialogues.py b/packages/valory/skills/offend_abci/dialogues.py similarity index 98% rename from packages/valory/skills/hello_world_abci/dialogues.py rename to packages/valory/skills/offend_abci/dialogues.py index e244bde0bd..e985dc8659 100644 --- a/packages/valory/skills/hello_world_abci/dialogues.py +++ b/packages/valory/skills/offend_abci/dialogues.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- # ------------------------------------------------------------------------------ # -# Copyright 2021-2023 Valory AG +# Copyright 2023 Valory AG # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/packages/valory/skills/offend_abci/fsm_specification.yaml b/packages/valory/skills/offend_abci/fsm_specification.yaml new file mode 100644 index 0000000000..7ee8fcbc4c --- /dev/null +++ b/packages/valory/skills/offend_abci/fsm_specification.yaml @@ -0,0 +1,17 @@ +alphabet_in: +- DONE +- NO_MAJORITY +- ROUND_TIMEOUT +default_start_state: OffendRound +final_states: +- FinishedOffendRound +label: OffendAbciApp +start_states: +- OffendRound +states: +- FinishedOffendRound +- OffendRound +transition_func: + (OffendRound, DONE): FinishedOffendRound + (OffendRound, NO_MAJORITY): OffendRound + (OffendRound, ROUND_TIMEOUT): OffendRound diff --git a/packages/valory/skills/hello_world_abci/handlers.py b/packages/valory/skills/offend_abci/handlers.py similarity index 94% rename from packages/valory/skills/hello_world_abci/handlers.py rename to packages/valory/skills/offend_abci/handlers.py index 742c479ee7..d424e92dc6 100644 --- a/packages/valory/skills/hello_world_abci/handlers.py +++ b/packages/valory/skills/offend_abci/handlers.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- # ------------------------------------------------------------------------------ # -# Copyright 2021-2023 Valory AG +# Copyright 2023 Valory AG # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -17,7 +17,7 @@ # # ------------------------------------------------------------------------------ -"""This module contains the handler for the Hello World skill.""" +"""This module contains the handler for the offend_abci skill.""" from packages.valory.skills.abstract_round_abci.handlers import ( ABCIRoundHandler as BaseABCIRoundHandler, diff --git a/packages/valory/skills/hello_world_abci/models.py b/packages/valory/skills/offend_abci/models.py similarity index 61% rename from packages/valory/skills/hello_world_abci/models.py rename to packages/valory/skills/offend_abci/models.py index a7bb5ba2f2..550e839174 100644 --- a/packages/valory/skills/hello_world_abci/models.py +++ b/packages/valory/skills/offend_abci/models.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- # ------------------------------------------------------------------------------ # -# Copyright 2021-2023 Valory AG +# Copyright 2023 Valory AG # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -17,11 +17,11 @@ # # ------------------------------------------------------------------------------ -"""This module contains the shared state for the Hello World application.""" +"""This module contains the shared state for the offend_abci skill.""" from typing import Any -from packages.valory.skills.abstract_round_abci.models import ApiSpecs, BaseParams +from packages.valory.skills.abstract_round_abci.models import BaseParams from packages.valory.skills.abstract_round_abci.models import ( BenchmarkTool as BaseBenchmarkTool, ) @@ -29,10 +29,7 @@ from packages.valory.skills.abstract_round_abci.models import ( SharedState as BaseSharedState, ) -from packages.valory.skills.hello_world_abci.rounds import Event, HelloWorldAbciApp - - -MARGIN = 5 +from packages.valory.skills.offend_abci.rounds import Event, OffendAbciApp Requests = BaseRequests @@ -42,26 +39,28 @@ class SharedState(BaseSharedState): """Keep the current shared state of the skill.""" - abci_app_cls = HelloWorldAbciApp + abci_app_cls = OffendAbciApp def setup(self) -> None: """Set up.""" super().setup() - HelloWorldAbciApp.event_to_timeout[ + OffendAbciApp.event_to_timeout[ Event.ROUND_TIMEOUT ] = self.context.params.round_timeout_seconds - HelloWorldAbciApp.event_to_timeout[Event.RESET_TIMEOUT] = ( - self.context.params.reset_pause_duration + MARGIN - ) -class HelloWorldParams(BaseParams): - """Hello World skill parameters.""" +class OffendParams(BaseParams): + """Offend skill's parameters.""" def __init__(self, *args: Any, **kwargs: Any) -> None: """Initialize the parameters.""" - self.hello_world_string: str = self._ensure("hello_world_message", kwargs, str) + self.validator_downtime: bool = self._ensure("validator_downtime", kwargs, bool) + self.invalid_payload: bool = self._ensure("invalid_payload", kwargs, bool) + self.blacklisted: bool = self._ensure("blacklisted", kwargs, bool) + self.suspected: bool = self._ensure("suspected", kwargs, bool) + self.num_unknown: int = self._ensure("num_unknown", kwargs, int) + self.num_double_signed: int = self._ensure("num_double_signed", kwargs, int) + self.num_light_client_attack: int = self._ensure( + "num_light_client_attack", kwargs, int + ) super().__init__(*args, **kwargs) - - -RandomnessApi = ApiSpecs diff --git a/packages/valory/skills/offend_abci/payloads.py b/packages/valory/skills/offend_abci/payloads.py new file mode 100644 index 0000000000..19342df282 --- /dev/null +++ b/packages/valory/skills/offend_abci/payloads.py @@ -0,0 +1,31 @@ +# -*- coding: utf-8 -*- +# ------------------------------------------------------------------------------ +# +# Copyright 2023 Valory AG +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# ------------------------------------------------------------------------------ + +"""This module contains the transaction payloads for the offend_abci skill.""" + +from dataclasses import dataclass + +from packages.valory.skills.abstract_round_abci.base import BaseTxPayload + + +@dataclass(frozen=True) +class OffencesPayload(BaseTxPayload): + """A payload for transferring offences.""" + + status: str diff --git a/packages/valory/skills/offend_abci/rounds.py b/packages/valory/skills/offend_abci/rounds.py new file mode 100644 index 0000000000..9a19d7085f --- /dev/null +++ b/packages/valory/skills/offend_abci/rounds.py @@ -0,0 +1,106 @@ +# -*- coding: utf-8 -*- +# ------------------------------------------------------------------------------ +# +# Copyright 2023 Valory AG +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# ------------------------------------------------------------------------------ + +"""This module contains the rounds for the offend_abci skill.""" + +import json +from enum import Enum +from typing import Dict, Optional, Set, Tuple + +from packages.valory.skills.abstract_round_abci.base import ( + AbciApp, + AbciAppTransitionFunction, + AppState, + BaseSynchronizedData, + CollectSameUntilThresholdRound, + DegenerateRound, + OffenseStatusDecoder, +) +from packages.valory.skills.offend_abci.payloads import OffencesPayload + + +class Event(Enum): + """Event enumeration for the Offend ABCI demo.""" + + DONE = "done" + ROUND_TIMEOUT = "round_timeout" + NO_MAJORITY = "no_majority" + + +class OffendRound(CollectSameUntilThresholdRound): + """A round in which the agents simulate an offence""" + + synchronized_data_class = BaseSynchronizedData + payload_class = OffencesPayload + + def end_block(self) -> Optional[Tuple[BaseSynchronizedData, Event]]: + """Process the end of the block.""" + + if self.threshold_reached: + self.context.state.round_sequence.offence_status = json.loads( + self.most_voted_payload, + cls=OffenseStatusDecoder, + ) + return self.synchronized_data, Event.DONE + if not self.is_majority_possible( + self.collection, self.synchronized_data.nb_participants + ): + return self.synchronized_data, Event.NO_MAJORITY + return None + + +class FinishedOffendRound(DegenerateRound): + """Indicates the completion of `OffendRound`.""" + + +class OffendAbciApp(AbciApp[Event]): + """OffendAbciApp + + Initial round: OffendRound + + Initial states: {OffendRound} + + Transition states: + 0. OffendRound + - done: 1. + - no majority: 0. + - round timeout: 0. + 1. FinishedOffendRound + + Final states: {FinishedOffendRound} + + Timeouts: + round timeout: 30.0 + """ + + initial_round_cls: AppState = OffendRound + transition_function: AbciAppTransitionFunction = { + OffendRound: { + Event.DONE: FinishedOffendRound, + Event.NO_MAJORITY: OffendRound, + Event.ROUND_TIMEOUT: OffendRound, + }, + FinishedOffendRound: {}, + } + final_states: Set[AppState] = {FinishedOffendRound} + event_to_timeout: Dict[Event, float] = { + Event.ROUND_TIMEOUT: 30.0, + } + db_pre_conditions: Dict[AppState, Set[str]] = {OffendRound: set()} + db_post_conditions: Dict[AppState, Set[str]] = {FinishedOffendRound: set()} diff --git a/packages/valory/skills/hello_world_abci/skill.yaml b/packages/valory/skills/offend_abci/skill.yaml similarity index 59% rename from packages/valory/skills/hello_world_abci/skill.yaml rename to packages/valory/skills/offend_abci/skill.yaml index 620899791b..cc1ac7f44f 100644 --- a/packages/valory/skills/hello_world_abci/skill.yaml +++ b/packages/valory/skills/offend_abci/skill.yaml @@ -1,37 +1,37 @@ -name: hello_world_abci +name: offend_abci author: valory version: 0.1.0 type: skill -description: Hello World ABCI application. +description: Offend ABCI application. license: Apache-2.0 aea_version: '>=1.0.0, <2.0.0' fingerprint: - README.md: bafybeidrjtykhovnccj3sovugdn4r3tszuzv7h37vta6o35epi5qfzdpke - __init__.py: bafybeibiblks3d3s3ditug4hfzl3ob3cibokcz4ofs7cbbsbqw5zzbtd3m - behaviours.py: bafybeiaai23italbrtlgpl7ie4pelhtrm6uqn773qap6jl5h4mj7fd553e - dialogues.py: bafybeigabhaykiyzbluu4mk6bbrmqhzld2kyp32pg24bvjmzrrb74einwm - fsm_specification.yaml: bafybeibaft2azersmixjtoa7zdekxzsvvnzfyq2zkyutx4elukc73owf5q - handlers.py: bafybeieyq37quymqq6md3hi5bvynifnkx73bcvmzct6difyvdkbzj6abaq - models.py: bafybeifyc3dezez4wbyexuy7q4do2xwlfrvtcvwsxgvg5cldeyvyi6ofju - payloads.py: bafybeiajaxhepvqsznhgadw24w4zumfpxcqysv7y4mdsnh5awvtvirpb3q - rounds.py: bafybeigtkugy35fv26tnj2kgyokh3ud2oa65neawiel4rdaclp6krtc7ti - tests/__init__.py: bafybeibpuwe63mjjwnaanx7wdw63reh6qa5xdtjxdf75o3nksvjercte4y - tests/test_behaviours.py: bafybeie6b5ibatxs4dlunkzj3b6k7al4ifgqyynh2qvbjekkbbnhlum4iy - tests/test_dialogues.py: bafybeiarl4wsnljaxkgxdwr47xd4xjjjtkfgqbtazt2v2oem47alhaykj4 - tests/test_handlers.py: bafybeigb2hfysb2v3yjiqemyy52h3onqalrufuqdnw2pnkowtuzvmvcrd4 - tests/test_models.py: bafybeibqrbnemkeurjag2fpqftlpo3df2vnbooid7hcw5nmlm4rhssle7q - tests/test_payloads.py: bafybeihgz46xtsaenago3bew5gxusyvbo4oivwqmv3r4oqwjgrnqoorcoe - tests/test_rounds.py: bafybeiftnts5nuclorvuwz46hmovufiz7cdetisd3ldbdqu4m3vfqodxau + README.md: bafybeic6ufinrstjvfoccnehekx3kmpgs6vpffmp7d5xqu7ghpxsfyxl7m + __init__.py: bafybeier4l5m6ib3awn3aaam6ykqybo33qoljq63lsfdsmhxqkzxfsk3ka + behaviours.py: bafybeietoverlxrntvhcjezoxjsnm3yflmtxmw2ho7cxvookiobc5nukga + dialogues.py: bafybeigpwuzku3we7axmxeamg7vn656maww6emuztau5pg3ebsoquyfdqm + fsm_specification.yaml: bafybeifdw3an6m65bortljjcqxuk4qek546ttkfuxkk4isbqnep62zqo2m + handlers.py: bafybeidb35i5zq5ichb3dxzsjdlqo4baltmtpldf4l7nw3uxaqa2cxaktq + models.py: bafybeigzu5qbghaniagvchbaamac4edl23djsb2dhfwuxs47f7n2fljfpi + payloads.py: bafybeiaew2vr65nm7gmm4qf5wh445wrwn7hbgm7hlx3jz7k2rucq73dj7m + rounds.py: bafybeie7j4a53uvmb7mw64hwqdkaricthckvduodmjpsslyr42w4633tie + tests/__init__.py: bafybeibdfveo3untltoeuvvv3nalsg2kilbwpxg6ypxax73b44nksva26m + tests/test_behaviours.py: bafybeievl6cyr5dmzu4r57urspvl4uy2yzty5a3mhrbxqmezn6ph6ycl2i + tests/test_dialogues.py: bafybeifqufxzmjmzph7ub2eucz3atgadl2lubf45xriaqgqgvck4yf5xs4 + tests/test_handlers.py: bafybeibamjqe73hlcexdrfauurmso77wxkbtvs4roednhynlyi7yr35com + tests/test_models.py: bafybeihmgqfxrolxozuhus3cscnaincmegu5zkx3z3rbhskb3ay2a5xrke + tests/test_payloads.py: bafybeiftpwgwjaezqateg63jk3onz5gfauldqqmajprkstjnzi6w6tkcwu + tests/test_rounds.py: bafybeidbmotdrqq7zp5lextvlim6xi3qvgncecfvxggi3bac6twlqsobcy fingerprint_ignore_patterns: [] connections: [] contracts: [] protocols: [] skills: -- valory/abstract_round_abci:0.1.0:bafybeigiolzp3i6b3wwuau3yv2h5udqape3i7of73mlm2d6ud22irlkbme +- valory/abstract_round_abci:0.1.0:bafybeicrzndcdbue34yxwwb4hmmdhgzw4owcdcdag3ifj6thpx5wie3dp4 behaviours: main: args: {} - class_name: HelloWorldRoundBehaviour + class_name: OffendRoundBehaviour handlers: abci: args: {} @@ -76,6 +76,7 @@ models: class_name: LedgerApiDialogues params: args: + blacklisted: false cleanup_history_depth: 1 cleanup_history_depth_current: null drand_public_key: 868f005eb8e6e4ca0a47c8a77ceaa5309a47978a7c71bc5cce96366b5d7a569937c529eeda66c7293784a9402801af31 @@ -96,10 +97,14 @@ models: - ed25519 version: {} voting_power: '10' - hello_world_message: HELLO_WORLD! + invalid_payload: false keeper_timeout: 30.0 + light_slash_unit_amount: 5000000000000000 max_attempts: 10 max_healthcheck: 120 + num_double_signed: 0 + num_light_client_attack: 0 + num_unknown: 0 on_chain_service_id: null request_retry_delay: 1.0 request_timeout: 10.0 @@ -108,7 +113,8 @@ models: retry_attempts: 400 retry_timeout: 3 round_timeout_seconds: 30.0 - service_id: hello_world_abci + serious_slash_unit_amount: 8000000000000000 + service_id: offend_abci service_registry_address: null setup: all_participants: @@ -116,26 +122,20 @@ models: safe_contract_address: '0x0000000000000000000000000000000000000000' consensus_threshold: null share_tm_config_on_startup: false + slash_cooldown_hours: 3 + slash_threshold_amount: 10000000000000000 sleep_time: 1 + suspected: false tendermint_check_sleep_delay: 3 tendermint_com_url: http://localhost:8080 tendermint_max_retries: 5 tendermint_p2p_url: localhost:26656 tendermint_url: http://localhost:26657 tx_timeout: 10.0 + use_slashing: false use_termination: false - class_name: HelloWorldParams - randomness_api: - args: - api_id: cloudflare - headers: {} - method: GET - parameters: {} - response_key: null - response_type: dict - retries: 5 - url: https://drand.cloudflare.com/public/latest - class_name: RandomnessApi + validator_downtime: false + class_name: OffendParams requests: args: {} class_name: Requests @@ -149,4 +149,4 @@ models: args: {} class_name: TendermintDialogues dependencies: {} -is_abstract: false +is_abstract: true diff --git a/packages/valory/agents/hello_world/tests/__init__.py b/packages/valory/skills/offend_abci/tests/__init__.py similarity index 91% rename from packages/valory/agents/hello_world/tests/__init__.py rename to packages/valory/skills/offend_abci/tests/__init__.py index b20bba12aa..732f023bf3 100644 --- a/packages/valory/agents/hello_world/tests/__init__.py +++ b/packages/valory/skills/offend_abci/tests/__init__.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- # ------------------------------------------------------------------------------ # -# Copyright 2022 Valory AG +# Copyright 2023 Valory AG # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -17,4 +17,4 @@ # # ------------------------------------------------------------------------------ -"""Tests for hello_world agent.""" +"""Tests for valory/offend_abci skill.""" diff --git a/packages/valory/skills/offend_abci/tests/test_behaviours.py b/packages/valory/skills/offend_abci/tests/test_behaviours.py new file mode 100644 index 0000000000..7af1c7fcdf --- /dev/null +++ b/packages/valory/skills/offend_abci/tests/test_behaviours.py @@ -0,0 +1,169 @@ +# -*- coding: utf-8 -*- +# ------------------------------------------------------------------------------ +# +# Copyright 2023 Valory AG +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# ------------------------------------------------------------------------------ + +"""Tests for valory/offend_abci skill's behaviours.""" + +from copy import deepcopy +from pathlib import Path +from typing import Any, cast + +import pytest + +from packages.valory.skills.abstract_round_abci.base import ( + AbciAppDB, + BaseSynchronizedData, + OffenceStatus, +) +from packages.valory.skills.abstract_round_abci.test_tools.base import ( + FSMBehaviourBaseCase, +) +from packages.valory.skills.offend_abci.behaviours import OffendBehaviour +from packages.valory.skills.offend_abci.rounds import Event, FinishedOffendRound + + +PACKAGE_DIR = Path(__file__).parents[1] + + +FIRST_PARTICIPANT = "a" +OTHER_PARTICIPANTS = ("c", "b", "d") +ALL_PARTICIPANTS = OTHER_PARTICIPANTS + (FIRST_PARTICIPANT,) +LIGHT_OFFENCE_UNIT_AMOUNT = 1 +SERIOUS_OFFENCE_UNIT_AMOUNT = 2 +INITIAL_OFFENCE_STATUS = { + participant: OffenceStatus() for participant in ALL_PARTICIPANTS +} + + +class TestOffendBehaviour(FSMBehaviourBaseCase): + """Test the `OffendBehaviour`.""" + + path_to_skill = PACKAGE_DIR + synchronized_data: BaseSynchronizedData + + @property + def current_behaviour(self) -> OffendBehaviour: + """Get the current behaviour.""" + return cast(OffendBehaviour, self.behaviour.current_behaviour) + + def setup(self, **kwargs: Any) -> None: + """ + Set up the test method. + + Called each time before a test method is called. + + :param kwargs: the keyword arguments passed to _prepare_skill + """ + super().setup(**kwargs) + self.synchronized_data = BaseSynchronizedData( + AbciAppDB( + setup_data=AbciAppDB.data_to_lists( + {"all_participants": ALL_PARTICIPANTS} + ) + ) + ) + self.fast_forward_to_behaviour( + self.behaviour, + OffendBehaviour.auto_behaviour_id(), + self.synchronized_data, + ) + assert self.current_behaviour is not None + assert ( + self.current_behaviour.behaviour_id == OffendBehaviour.auto_behaviour_id() + ) + + self.current_behaviour.context.state.round_sequence.offence_status = deepcopy( + INITIAL_OFFENCE_STATUS + ) + + self.current_behaviour.params.__dict__["_frozen"] = False + self.current_behaviour.params.suspected = True + self.current_behaviour.params.__dict__["_frozen"] = True + + @pytest.mark.parametrize( + ( + "suspected", + "validator_downtime", + "invalid_payload", + "blacklisted", + "num_unknown", + "num_double_signed", + "num_light_client_attack", + "expected_slash_amount", + ), + ( + (False, False, False, False, 0, 0, 0, 0), + (True, False, False, False, 0, 0, 0, 1), + (False, True, False, False, 0, 0, 0, 1), + (False, False, True, False, 0, 0, 0, 1), + (False, False, False, True, 0, 0, 0, 1), + (False, False, False, False, 1, 0, 0, 2), + (False, False, False, False, 0, 1, 0, 2), + (False, False, False, False, 0, 0, 1, 2), + (False, False, False, False, 0, 2, 1, 6), + (False, True, False, True, 5, 2, 1, 18), + (True, True, True, True, 5, 2, 1, 20), + ), + ) + def test_updated_status( # pylint: disable=too-many-arguments + self, + suspected: bool, + validator_downtime: bool, + invalid_payload: bool, + blacklisted: bool, + num_unknown: int, + num_double_signed: int, + num_light_client_attack: int, + expected_slash_amount: str, + ) -> None: + """Test the `_updated_status` method.""" + self.current_behaviour.params.__dict__["_frozen"] = False + self.current_behaviour.params.suspected = suspected + self.current_behaviour.params.validator_downtime = validator_downtime + self.current_behaviour.params.invalid_payload = invalid_payload + self.current_behaviour.params.blacklisted = blacklisted + self.current_behaviour.params.num_unknown = num_unknown + self.current_behaviour.params.num_double_signed = num_double_signed + self.current_behaviour.params.num_light_client_attack = num_light_client_attack + self.current_behaviour.params.__dict__["_frozen"] = True + + status = ( + self.current_behaviour._updated_status() # pylint: disable=protected-access + ) + + actual_slash_amount = status[FIRST_PARTICIPANT].slash_amount( + LIGHT_OFFENCE_UNIT_AMOUNT, SERIOUS_OFFENCE_UNIT_AMOUNT + ) + assert actual_slash_amount == expected_slash_amount + + for participant in OTHER_PARTICIPANTS: + actual_slash_amount = status[participant].slash_amount( + LIGHT_OFFENCE_UNIT_AMOUNT, SERIOUS_OFFENCE_UNIT_AMOUNT + ) + assert actual_slash_amount == 0 + + def test_offend_act(self) -> None: + """Test offend behaviour's `async_act` method.""" + self.behaviour.act_wrapper() + self.mock_a2a_transaction() + status = self.current_behaviour.shared_state.round_sequence.offence_status + assert status == INITIAL_OFFENCE_STATUS + self._test_done_flag_set() + self.end_round(Event.DONE) + expected_id = f"degenerate_behaviour_{FinishedOffendRound.auto_round_id()}" + assert self.current_behaviour.behaviour_id == expected_id diff --git a/packages/valory/skills/hello_world_abci/tests/test_dialogues.py b/packages/valory/skills/offend_abci/tests/test_dialogues.py similarity index 88% rename from packages/valory/skills/hello_world_abci/tests/test_dialogues.py rename to packages/valory/skills/offend_abci/tests/test_dialogues.py index fdcc08ed13..555c8f08b8 100644 --- a/packages/valory/skills/hello_world_abci/tests/test_dialogues.py +++ b/packages/valory/skills/offend_abci/tests/test_dialogues.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- # ------------------------------------------------------------------------------ # -# Copyright 2021-2022 Valory AG +# Copyright 2023 Valory AG # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -19,9 +19,7 @@ """Test the dialogues.py module of the skill.""" -# pylint: skip-file - -import packages.valory.skills.hello_world_abci.dialogues # noqa +import packages.valory.skills.offend_abci.dialogues # noqa # pylint: disable=unused-import def test_import() -> None: diff --git a/packages/valory/skills/hello_world_abci/tests/test_handlers.py b/packages/valory/skills/offend_abci/tests/test_handlers.py similarity index 88% rename from packages/valory/skills/hello_world_abci/tests/test_handlers.py rename to packages/valory/skills/offend_abci/tests/test_handlers.py index 00e8eb5f50..7268b50b41 100644 --- a/packages/valory/skills/hello_world_abci/tests/test_handlers.py +++ b/packages/valory/skills/offend_abci/tests/test_handlers.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- # ------------------------------------------------------------------------------ # -# Copyright 2021-2022 Valory AG +# Copyright 2023 Valory AG # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -19,10 +19,7 @@ """Test the dialogues.py module of the skill.""" -import packages.valory.skills.hello_world_abci.handlers # noqa - - -# pylint: skip-file +import packages.valory.skills.offend_abci.handlers # noqa # pylint: disable=unused-import def test_import() -> None: diff --git a/packages/valory/skills/offend_abci/tests/test_models.py b/packages/valory/skills/offend_abci/tests/test_models.py new file mode 100644 index 0000000000..17427aca6a --- /dev/null +++ b/packages/valory/skills/offend_abci/tests/test_models.py @@ -0,0 +1,78 @@ +# -*- coding: utf-8 -*- +# ------------------------------------------------------------------------------ +# +# Copyright 2023 Valory AG +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# ------------------------------------------------------------------------------ + +"""Test the models.py module of the skill.""" + +from unittest.mock import MagicMock + +from hypothesis import given, settings +from hypothesis import strategies as st + +from packages.valory.skills.abstract_round_abci.tests.conftest import ( + irrelevant_config, + profile_name, +) +from packages.valory.skills.offend_abci.models import OffendParams, SharedState +from packages.valory.skills.offend_abci.rounds import Event, OffendAbciApp + + +settings.load_profile(profile_name) + + +class TestModels: + """Test the models.""" + + @staticmethod + def test_setup() -> None: + """Test `SharedState`'s `setup`.""" + shared_state = SharedState(name="", skill_context=MagicMock()) + shared_state.context.params.setup_params = {"test": []} + shared_state.setup() + assert ( + OffendAbciApp.event_to_timeout[Event.ROUND_TIMEOUT] + == shared_state.context.params.round_timeout_seconds + ) + + @staticmethod + @given( + offend_config=st.fixed_dictionaries( + dict( + validator_downtime=st.booleans(), + invalid_payload=st.booleans(), + blacklisted=st.booleans(), + suspected=st.booleans(), + num_unknown=st.integers(), + num_double_signed=st.integers(), + num_light_client_attack=st.integers(), + ) + ) + ) + def test_init(offend_config: dict) -> None: + """Test the initialization of the `OffendParams`.""" + base_config = dict( + name="test", + skill_context=MagicMock(), + service_id="test", + ) + params = OffendParams( + **base_config, + **offend_config, + **irrelevant_config, + ) + assert all(getattr(params, name) == val for name, val in offend_config.items()) diff --git a/packages/valory/skills/offend_abci/tests/test_payloads.py b/packages/valory/skills/offend_abci/tests/test_payloads.py new file mode 100644 index 0000000000..2c3779cc5e --- /dev/null +++ b/packages/valory/skills/offend_abci/tests/test_payloads.py @@ -0,0 +1,33 @@ +# -*- coding: utf-8 -*- +# ------------------------------------------------------------------------------ +# +# Copyright 2023 Valory AG +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# ------------------------------------------------------------------------------ + +"""Test the payloads.py module of the skill.""" + +from packages.valory.skills.offend_abci.payloads import OffencesPayload + + +def test_offences_payload() -> None: + """Test `OffencesPayload`.""" + + payload = OffencesPayload("sender", "dummy_status") + + assert payload.sender == "sender" + assert payload.id_ + assert payload.status == "dummy_status" + assert payload.data == {"status": "dummy_status"} diff --git a/packages/valory/skills/offend_abci/tests/test_rounds.py b/packages/valory/skills/offend_abci/tests/test_rounds.py new file mode 100644 index 0000000000..42cb7028fd --- /dev/null +++ b/packages/valory/skills/offend_abci/tests/test_rounds.py @@ -0,0 +1,90 @@ +# -*- coding: utf-8 -*- +# ------------------------------------------------------------------------------ +# +# Copyright 2023 Valory AG +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# ------------------------------------------------------------------------------ + +"""Test the rounds of the skill.""" + +import json +from typing import Dict +from unittest.mock import MagicMock + +from packages.valory.skills.abstract_round_abci.base import ( + BaseSynchronizedData, + OffenceStatus, + OffenseStatusEncoder, +) +from packages.valory.skills.abstract_round_abci.test_tools.rounds import ( + BaseCollectSameUntilThresholdRoundTest, +) +from packages.valory.skills.offend_abci.payloads import OffencesPayload +from packages.valory.skills.offend_abci.rounds import Event, OffendRound + + +class TestOffendRound(BaseCollectSameUntilThresholdRoundTest): + """Tests for OffendRound.""" + + _synchronized_data_class = BaseSynchronizedData + _event_class = Event + + @property + def status( + self, + ) -> Dict[str, OffenceStatus]: + """Get a stub offence status.""" + return {participant: OffenceStatus() for participant in self.participants} + + @property + def serialized_status( + self, + ) -> str: + """Get a stub offence status, serialized.""" + return json.dumps(self.status, cls=OffenseStatusEncoder, sort_keys=True) + + @property + def participant_to_offend( + self, + ) -> Dict[str, OffencesPayload]: + """Get participant to offend payload mapping.""" + return { + participant: OffencesPayload(participant, self.serialized_status) + for participant in self.participants + } + + def test_run(self) -> None: + """Runs test.""" + context_mock = MagicMock() + context_mock.state.round_sequence.offence_status = None + test_round = OffendRound(self.synchronized_data, context_mock) + + self._complete_run( + self._test_round( + test_round=test_round, + round_payloads=self.participant_to_offend, + synchronized_data_update_fn=lambda _synchronized_data, _: _synchronized_data, + synchronized_data_attr_checks=[], + most_voted_payload=self.serialized_status, + exit_event=Event.DONE, + ) + ) + + assert context_mock.state.round_sequence.offence_status == self.status + + def test_no_majority_event(self) -> None: + """Test the no-majority event.""" + test_round = OffendRound(self.synchronized_data, MagicMock()) + self._test_no_majority_event(test_round) diff --git a/packages/valory/skills/offend_slash_abci/README.md b/packages/valory/skills/offend_slash_abci/README.md new file mode 100644 index 0000000000..41eac29645 --- /dev/null +++ b/packages/valory/skills/offend_slash_abci/README.md @@ -0,0 +1,5 @@ +# Offend Slash abci + +## Description + +This module contains a skill used to showcase the slashing abci. diff --git a/packages/valory/skills/offend_slash_abci/__init__.py b/packages/valory/skills/offend_slash_abci/__init__.py new file mode 100644 index 0000000000..037a2586fa --- /dev/null +++ b/packages/valory/skills/offend_slash_abci/__init__.py @@ -0,0 +1,29 @@ +# -*- coding: utf-8 -*- +# ------------------------------------------------------------------------------ +# +# Copyright 2023 Valory AG +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# ------------------------------------------------------------------------------ + +""" +This module contains a dummy ABCI skill in which some agent performs an offence and gets slashed. + +It is created only for testing purposes for the slashing feature. +""" + +from aea.configurations.base import PublicId + + +PUBLIC_ID = PublicId.from_str("valory/offend_slash_abci:0.1.0") diff --git a/packages/valory/skills/offend_slash_abci/behaviours.py b/packages/valory/skills/offend_slash_abci/behaviours.py new file mode 100644 index 0000000000..e0b537b3da --- /dev/null +++ b/packages/valory/skills/offend_slash_abci/behaviours.py @@ -0,0 +1,54 @@ +# -*- coding: utf-8 -*- +# ------------------------------------------------------------------------------ +# +# Copyright 2023 Valory AG +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# ------------------------------------------------------------------------------ + +"""This module contains the behaviours for the 'offend_slash_abci' skill.""" + +from typing import Set, Type + +from packages.valory.skills.abstract_round_abci.behaviours import ( + AbstractRoundBehaviour, + BaseBehaviour, +) +from packages.valory.skills.offend_abci.behaviours import OffendRoundBehaviour +from packages.valory.skills.offend_slash_abci.composition import OffendSlashAbciApp +from packages.valory.skills.registration_abci.behaviours import ( + AgentRegistrationRoundBehaviour, + RegistrationStartupBehaviour, +) +from packages.valory.skills.reset_pause_abci.behaviours import ( + ResetPauseABCIConsensusBehaviour, +) +from packages.valory.skills.slashing_abci.behaviours import ( + SlashingAbciBehaviours, + SlashingCheckBehaviour, +) + + +class OffendSlashAbciAppConsensusBehaviour(AbstractRoundBehaviour): + """This behaviour manages the consensus stages for the offend_slash_abci.""" + + initial_behaviour_cls = RegistrationStartupBehaviour + abci_app_cls = OffendSlashAbciApp + behaviours: Set[Type[BaseBehaviour]] = { + *AgentRegistrationRoundBehaviour.behaviours, + *OffendRoundBehaviour.behaviours, + *ResetPauseABCIConsensusBehaviour.behaviours, + *SlashingAbciBehaviours.behaviours, + } + background_behaviours_cls = {SlashingCheckBehaviour} diff --git a/packages/valory/skills/offend_slash_abci/composition.py b/packages/valory/skills/offend_slash_abci/composition.py new file mode 100644 index 0000000000..db67b34b5a --- /dev/null +++ b/packages/valory/skills/offend_slash_abci/composition.py @@ -0,0 +1,55 @@ +# -*- coding: utf-8 -*- +# ------------------------------------------------------------------------------ +# +# Copyright 2023 Valory AG +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# ------------------------------------------------------------------------------ + +"""This module contains the offend_slash_abci application.""" + +import packages.valory.skills.offend_abci.rounds as OffendAbci +import packages.valory.skills.registration_abci.rounds as RegistrationAbci +import packages.valory.skills.reset_pause_abci.rounds as ResetAndPauseAbci +from packages.valory.skills.abstract_round_abci.abci_app_chain import ( + AbciAppTransitionMapping, + chain, +) +from packages.valory.skills.abstract_round_abci.base import BackgroundAppConfig +from packages.valory.skills.slashing_abci.composition import SlashingAbciApp +from packages.valory.skills.slashing_abci.rounds import Event, SlashingCheckRound + + +abci_app_transition_mapping: AbciAppTransitionMapping = { + RegistrationAbci.FinishedRegistrationRound: OffendAbci.OffendRound, + OffendAbci.FinishedOffendRound: ResetAndPauseAbci.ResetAndPauseRound, + ResetAndPauseAbci.FinishedResetAndPauseRound: OffendAbci.OffendRound, + ResetAndPauseAbci.FinishedResetAndPauseErrorRound: ResetAndPauseAbci.ResetAndPauseRound, +} + +slashing_config = BackgroundAppConfig( + round_cls=SlashingCheckRound, + start_event=Event.SLASH_START, + end_event=Event.SLASH_END, + abci_app=SlashingAbciApp, +) + +OffendSlashAbciApp = chain( + ( + RegistrationAbci.AgentRegistrationAbciApp, + OffendAbci.OffendAbciApp, + ResetAndPauseAbci.ResetPauseAbciApp, + ), + abci_app_transition_mapping, +).add_background_app(slashing_config) diff --git a/packages/valory/skills/offend_slash_abci/dialogues.py b/packages/valory/skills/offend_slash_abci/dialogues.py new file mode 100644 index 0000000000..e985dc8659 --- /dev/null +++ b/packages/valory/skills/offend_slash_abci/dialogues.py @@ -0,0 +1,91 @@ +# -*- coding: utf-8 -*- +# ------------------------------------------------------------------------------ +# +# Copyright 2023 Valory AG +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# ------------------------------------------------------------------------------ + +"""This module contains the classes required for dialogue management.""" + +from packages.valory.skills.abstract_round_abci.dialogues import ( + AbciDialogue as BaseAbciDialogue, +) +from packages.valory.skills.abstract_round_abci.dialogues import ( + AbciDialogues as BaseAbciDialogues, +) +from packages.valory.skills.abstract_round_abci.dialogues import ( + ContractApiDialogue as BaseContractApiDialogue, +) +from packages.valory.skills.abstract_round_abci.dialogues import ( + ContractApiDialogues as BaseContractApiDialogues, +) +from packages.valory.skills.abstract_round_abci.dialogues import ( + HttpDialogue as BaseHttpDialogue, +) +from packages.valory.skills.abstract_round_abci.dialogues import ( + HttpDialogues as BaseHttpDialogues, +) +from packages.valory.skills.abstract_round_abci.dialogues import ( + IpfsDialogue as BaseIpfsDialogue, +) +from packages.valory.skills.abstract_round_abci.dialogues import ( + IpfsDialogues as BaseIpfsDialogues, +) +from packages.valory.skills.abstract_round_abci.dialogues import ( + LedgerApiDialogue as BaseLedgerApiDialogue, +) +from packages.valory.skills.abstract_round_abci.dialogues import ( + LedgerApiDialogues as BaseLedgerApiDialogues, +) +from packages.valory.skills.abstract_round_abci.dialogues import ( + SigningDialogue as BaseSigningDialogue, +) +from packages.valory.skills.abstract_round_abci.dialogues import ( + SigningDialogues as BaseSigningDialogues, +) +from packages.valory.skills.abstract_round_abci.dialogues import ( + TendermintDialogue as BaseTendermintDialogue, +) +from packages.valory.skills.abstract_round_abci.dialogues import ( + TendermintDialogues as BaseTendermintDialogues, +) + + +AbciDialogue = BaseAbciDialogue +AbciDialogues = BaseAbciDialogues + + +HttpDialogue = BaseHttpDialogue +HttpDialogues = BaseHttpDialogues + + +SigningDialogue = BaseSigningDialogue +SigningDialogues = BaseSigningDialogues + + +LedgerApiDialogue = BaseLedgerApiDialogue +LedgerApiDialogues = BaseLedgerApiDialogues + + +ContractApiDialogue = BaseContractApiDialogue +ContractApiDialogues = BaseContractApiDialogues + + +TendermintDialogue = BaseTendermintDialogue +TendermintDialogues = BaseTendermintDialogues + + +IpfsDialogue = BaseIpfsDialogue +IpfsDialogues = BaseIpfsDialogues diff --git a/packages/valory/skills/offend_slash_abci/handlers.py b/packages/valory/skills/offend_slash_abci/handlers.py new file mode 100644 index 0000000000..95382003b8 --- /dev/null +++ b/packages/valory/skills/offend_slash_abci/handlers.py @@ -0,0 +1,51 @@ +# -*- coding: utf-8 -*- +# ------------------------------------------------------------------------------ +# +# Copyright 2023 Valory AG +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# ------------------------------------------------------------------------------ + +"""This module contains the handler for the offend_slash_abci.""" + +from packages.valory.skills.abstract_round_abci.handlers import ( + ABCIRoundHandler as BaseABCIRoundHandler, +) +from packages.valory.skills.abstract_round_abci.handlers import ( + ContractApiHandler as BaseContractApiHandler, +) +from packages.valory.skills.abstract_round_abci.handlers import ( + HttpHandler as BaseHttpHandler, +) +from packages.valory.skills.abstract_round_abci.handlers import ( + IpfsHandler as BaseIpfsHandler, +) +from packages.valory.skills.abstract_round_abci.handlers import ( + LedgerApiHandler as BaseLedgerApiHandler, +) +from packages.valory.skills.abstract_round_abci.handlers import ( + SigningHandler as BaseSigningHandler, +) +from packages.valory.skills.abstract_round_abci.handlers import ( + TendermintHandler as BaseTendermintHandler, +) + + +ABCIHandler = BaseABCIRoundHandler +HttpHandler = BaseHttpHandler +SigningHandler = BaseSigningHandler +LedgerApiHandler = BaseLedgerApiHandler +ContractApiHandler = BaseContractApiHandler +TendermintHandler = BaseTendermintHandler +IpfsHandler = BaseIpfsHandler diff --git a/packages/valory/skills/offend_slash_abci/models.py b/packages/valory/skills/offend_slash_abci/models.py new file mode 100644 index 0000000000..2e79134479 --- /dev/null +++ b/packages/valory/skills/offend_slash_abci/models.py @@ -0,0 +1,49 @@ +# -*- coding: utf-8 -*- +# ------------------------------------------------------------------------------ +# +# Copyright 2023 Valory AG +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# ------------------------------------------------------------------------------ + +"""This module contains the shared state for the offend_slash_abci application.""" + +from packages.valory.skills.abstract_round_abci.models import ( + BenchmarkTool as BaseBenchmarkTool, +) +from packages.valory.skills.abstract_round_abci.models import Requests as BaseRequests +from packages.valory.skills.abstract_round_abci.models import ( + SharedState as BaseSharedState, +) +from packages.valory.skills.offend_abci.models import OffendParams +from packages.valory.skills.offend_slash_abci.composition import OffendSlashAbciApp +from packages.valory.skills.slashing_abci.models import ( + RandomnessApi as SlashingRandomness, +) +from packages.valory.skills.slashing_abci.models import SlashingParams + + +Requests = BaseRequests +BenchmarkTool = BaseBenchmarkTool +RandomnessApi = SlashingRandomness + + +class Params(OffendParams, SlashingParams): + """`offend_slash` skill's parameters.""" + + +class SharedState(BaseSharedState): + """Keep the current shared state of the skill.""" + + abci_app_cls = OffendSlashAbciApp diff --git a/packages/valory/skills/offend_slash_abci/skill.yaml b/packages/valory/skills/offend_slash_abci/skill.yaml new file mode 100644 index 0000000000..bcb9a47718 --- /dev/null +++ b/packages/valory/skills/offend_slash_abci/skill.yaml @@ -0,0 +1,167 @@ +name: offend_slash_abci +author: valory +version: 0.1.0 +type: skill +description: ABCI application used in order to test the slashing abci +license: Apache-2.0 +aea_version: '>=1.0.0, <2.0.0' +fingerprint: + README.md: bafybeiff3e5cjvl74rtybyvodggnsxubw7agw37epoagwrpz6g2szufmxa + __init__.py: bafybeiaopodjnkdcukf3vw4racq552bzt22uh5oioebcaklwpnvjyihpfy + behaviours.py: bafybeices54uowgfsq67funxpl2b7k7xxbshiorgrrkmncdhqrcwnothnq + composition.py: bafybeihoddfltsv4nt34qstcw77ttoiwqssgaqhtgj4na7534wz4cq7sge + dialogues.py: bafybeigpwuzku3we7axmxeamg7vn656maww6emuztau5pg3ebsoquyfdqm + handlers.py: bafybeifnzry2revihwvjkvc6aqbbsdwvauw7jqv253m5clc23qbwepxfzu + models.py: bafybeiaoxx4n7c2zc4pcphh5laxil2d2ejq6kjbghb3rkt26a5utymnpva + tests/__init__.py: bafybeihg5ifbullyt64anjht5vlmspr6byo4rk6arcg5ufzmmw6xr5t77i + tests/test_behaviours.py: bafybeiajcitxmshmwgkeizd4dnhb34t2w47wxh7lhcizhoimijnfgvswaq + tests/test_dialogues.py: bafybeibb3tlcp7cz76iounglv32tjgebclqi3wm4cslxf3neyeibyqy5t4 + tests/test_handlers.py: bafybeif65ihrcfmhidos4wyq3ub2cbhhsrezanr3r3jyhgfhuxetjjl6im + tests/test_models.py: bafybeiectmzpvdgytmqt6b2rc22qx2bogudm7mtkcc2ol4q3l3ayvmx7sa +fingerprint_ignore_patterns: [] +connections: [] +contracts: [] +protocols: [] +skills: +- valory/abstract_round_abci:0.1.0:bafybeicrzndcdbue34yxwwb4hmmdhgzw4owcdcdag3ifj6thpx5wie3dp4 +- valory/offend_abci:0.1.0:bafybeifhczaajqghtwo754aukhy2uyollmksgxnofowem67wy5ie5ezmvm +- valory/registration_abci:0.1.0:bafybeihjlapvviakobxg7aa5qubgqoz6xurlhu7xxtnrg5ah3ag2qj626i +- valory/reset_pause_abci:0.1.0:bafybeibnwjcjx4lluf4cwb6es5peelu3gm7vrzlieygrzpbjlubxpvbvzy +- valory/slashing_abci:0.1.0:bafybeievvfagzeod4ivbx7dmnmybrmodkzuav7kjz4wjjr3cagslsyh6oy +behaviours: + main: + args: {} + class_name: OffendSlashAbciAppConsensusBehaviour +handlers: + abci: + args: {} + class_name: ABCIHandler + contract_api: + args: {} + class_name: ContractApiHandler + http: + args: {} + class_name: HttpHandler + ledger_api: + args: {} + class_name: LedgerApiHandler + signing: + args: {} + class_name: SigningHandler + tendermint: + args: {} + class_name: TendermintHandler +models: + abci_dialogues: + args: {} + class_name: AbciDialogues + benchmark_tool: + args: + log_dir: /logs + class_name: BenchmarkTool + contract_api_dialogues: + args: {} + class_name: ContractApiDialogues + http_dialogues: + args: {} + class_name: HttpDialogues + ipfs_dialogues: + args: {} + class_name: IpfsDialogues + ledger_api_dialogues: + args: {} + class_name: LedgerApiDialogues + params: + args: + blacklisted: false + cleanup_history_depth: 1 + cleanup_history_depth_current: null + drand_public_key: 868f005eb8e6e4ca0a47c8a77ceaa5309a47978a7c71bc5cce96366b5d7a569937c529eeda66c7293784a9402801af31 + finalize_timeout: 60.0 + genesis_config: + genesis_time: '2022-05-20T16:00:21.735122717Z' + chain_id: chain-c4daS1 + consensus_params: + block: + max_bytes: '22020096' + max_gas: '-1' + time_iota_ms: '1000' + evidence: + max_age_num_blocks: '100000' + max_age_duration: '172800000000000' + max_bytes: '1048576' + validator: + pub_key_types: + - ed25519 + version: {} + voting_power: '10' + history_check_timeout: 1205 + init_fallback_gas: 0 + invalid_payload: false + keeper_allowed_retries: 3 + keeper_timeout: 30.0 + light_slash_unit_amount: 5000000000000000 + max_attempts: 10 + max_healthcheck: 120 + multisend_address: null + num_double_signed: 0 + num_light_client_attack: 0 + num_unknown: 0 + on_chain_service_id: null + request_retry_delay: 1.0 + request_timeout: 10.0 + reset_pause_duration: 10 + reset_tendermint_after: 200 + retry_attempts: 400 + retry_timeout: 3 + round_timeout_seconds: 15.0 + serious_slash_unit_amount: 8000000000000000 + service_id: register_termination_abci + service_registry_address: null + setup: + all_participants: + - '0x0000000000000000000000000000000000000000' + safe_contract_address: '0x77b783e911F4398D75908Cc60C7138Bd1eFe35Fd' + consensus_threshold: null + share_tm_config_on_startup: false + slash_cooldown_hours: 3 + slash_threshold_amount: 10000000000000000 + sleep_time: 1 + suspected: false + tendermint_check_sleep_delay: 3 + tendermint_com_url: http://localhost:8080 + tendermint_max_retries: 5 + tendermint_p2p_url: localhost:26656 + tendermint_url: http://localhost:26657 + termination_sleep: 900 + tx_timeout: 10.0 + use_slashing: true + use_termination: false + validate_timeout: 1205 + validator_downtime: false + class_name: Params + randomness_api: + args: + api_id: cloudflare + headers: {} + method: GET + parameters: {} + response_key: null + response_type: dict + retries: 5 + url: https://drand.cloudflare.com/public/latest + class_name: RandomnessApi + requests: + args: {} + class_name: Requests + signing_dialogues: + args: {} + class_name: SigningDialogues + state: + args: {} + class_name: SharedState + tendermint_dialogues: + args: {} + class_name: TendermintDialogues +dependencies: {} +is_abstract: false diff --git a/packages/valory/skills/offend_slash_abci/tests/__init__.py b/packages/valory/skills/offend_slash_abci/tests/__init__.py new file mode 100644 index 0000000000..ac8153710f --- /dev/null +++ b/packages/valory/skills/offend_slash_abci/tests/__init__.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# ------------------------------------------------------------------------------ +# +# Copyright 2023 Valory AG +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# ------------------------------------------------------------------------------ + +"""Tests for valory/offend_slash_abci skill.""" diff --git a/packages/valory/skills/offend_slash_abci/tests/test_behaviours.py b/packages/valory/skills/offend_slash_abci/tests/test_behaviours.py new file mode 100644 index 0000000000..7fc459a873 --- /dev/null +++ b/packages/valory/skills/offend_slash_abci/tests/test_behaviours.py @@ -0,0 +1,56 @@ +# -*- coding: utf-8 -*- +# ------------------------------------------------------------------------------ +# +# Copyright 2023 Valory AG +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# ------------------------------------------------------------------------------ + +"""Tests for valory/offend_slash_abci skill's behaviours.""" + +from unittest.mock import MagicMock + +from packages.valory.skills.offend_abci.behaviours import OffendRoundBehaviour +from packages.valory.skills.offend_slash_abci.behaviours import ( + OffendSlashAbciAppConsensusBehaviour, +) +from packages.valory.skills.offend_slash_abci.composition import OffendSlashAbciApp +from packages.valory.skills.registration_abci.behaviours import ( + AgentRegistrationRoundBehaviour, + RegistrationStartupBehaviour, +) +from packages.valory.skills.reset_pause_abci.behaviours import ( + ResetPauseABCIConsensusBehaviour, +) +from packages.valory.skills.slashing_abci.behaviours import ( + SlashingAbciBehaviours, + SlashingCheckBehaviour, +) + + +def test_chained_behaviour() -> None: + """Test `OffendSlashAbciAppConsensusBehaviour`.""" + + behaviour = OffendSlashAbciAppConsensusBehaviour( + name="dummy_name", skill_context=MagicMock() + ) + assert behaviour.initial_behaviour_cls == RegistrationStartupBehaviour + assert behaviour.abci_app_cls == OffendSlashAbciApp + assert behaviour.behaviours == { + *AgentRegistrationRoundBehaviour.behaviours, + *OffendRoundBehaviour.behaviours, + *ResetPauseABCIConsensusBehaviour.behaviours, + *SlashingAbciBehaviours.behaviours, + } + assert behaviour.background_behaviours_cls == {SlashingCheckBehaviour} diff --git a/packages/valory/skills/offend_slash_abci/tests/test_dialogues.py b/packages/valory/skills/offend_slash_abci/tests/test_dialogues.py new file mode 100644 index 0000000000..9114b38eed --- /dev/null +++ b/packages/valory/skills/offend_slash_abci/tests/test_dialogues.py @@ -0,0 +1,28 @@ +# -*- coding: utf-8 -*- +# ------------------------------------------------------------------------------ +# +# Copyright 2023 Valory AG +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# ------------------------------------------------------------------------------ + + +"""Test the dialogues.py module of the skill.""" + + +import packages.valory.skills.offend_slash_abci.dialogues # noqa # pylint: disable=unused-import + + +def test_import() -> None: + """Test that the 'dialogues.py' Python module can be imported.""" diff --git a/packages/valory/skills/offend_slash_abci/tests/test_handlers.py b/packages/valory/skills/offend_slash_abci/tests/test_handlers.py new file mode 100644 index 0000000000..f682e66001 --- /dev/null +++ b/packages/valory/skills/offend_slash_abci/tests/test_handlers.py @@ -0,0 +1,28 @@ +# -*- coding: utf-8 -*- +# ------------------------------------------------------------------------------ +# +# Copyright 2023 Valory AG +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# ------------------------------------------------------------------------------ + + +"""Test the dialogues.py module of the skill.""" + + +import packages.valory.skills.offend_slash_abci.handlers # noqa # pylint: disable=unused-import + + +def test_import() -> None: + """Test that the 'handlers.py' Python module can be imported.""" diff --git a/packages/valory/skills/offend_slash_abci/tests/test_models.py b/packages/valory/skills/offend_slash_abci/tests/test_models.py new file mode 100644 index 0000000000..8b59fdeff8 --- /dev/null +++ b/packages/valory/skills/offend_slash_abci/tests/test_models.py @@ -0,0 +1,34 @@ +# -*- coding: utf-8 -*- +# ------------------------------------------------------------------------------ +# +# Copyright 2023 Valory AG +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# ------------------------------------------------------------------------------ + + +"""Test the models.py module of the skill.""" + + +from packages.valory.skills.abstract_round_abci.test_tools.base import DummyContext +from packages.valory.skills.offend_slash_abci.models import SharedState + + +class TestSharedState: # pylint: disable=too-few-public-methods + """Test `SharedState` class.""" + + @staticmethod + def test_initialization() -> None: + """Test initialization.""" + SharedState(name="", skill_context=DummyContext()) diff --git a/packages/valory/skills/register_reset_abci/skill.yaml b/packages/valory/skills/register_reset_abci/skill.yaml index c211e8b990..fbc881c334 100644 --- a/packages/valory/skills/register_reset_abci/skill.yaml +++ b/packages/valory/skills/register_reset_abci/skill.yaml @@ -24,9 +24,9 @@ connections: [] contracts: [] protocols: [] skills: -- valory/abstract_round_abci:0.1.0:bafybeigiolzp3i6b3wwuau3yv2h5udqape3i7of73mlm2d6ud22irlkbme -- valory/registration_abci:0.1.0:bafybeigjzfdhhu6ody2qo5v2xjobafujnodklia4zw6bkkhahxtjfo3wby -- valory/reset_pause_abci:0.1.0:bafybeieeux3rdlcwgjbdfrluvkhqv26qdparre6pabatietw7juklljil4 +- valory/abstract_round_abci:0.1.0:bafybeicrzndcdbue34yxwwb4hmmdhgzw4owcdcdag3ifj6thpx5wie3dp4 +- valory/registration_abci:0.1.0:bafybeihjlapvviakobxg7aa5qubgqoz6xurlhu7xxtnrg5ah3ag2qj626i +- valory/reset_pause_abci:0.1.0:bafybeibnwjcjx4lluf4cwb6es5peelu3gm7vrzlieygrzpbjlubxpvbvzy behaviours: main: args: {} @@ -97,6 +97,7 @@ models: voting_power: '10' ipfs_domain_name: null keeper_timeout: 30.0 + light_slash_unit_amount: 5000000000000000 max_attempts: 10 max_healthcheck: 120 on_chain_service_id: null @@ -107,6 +108,7 @@ models: retry_attempts: 400 retry_timeout: 3 round_timeout_seconds: 15.0 + serious_slash_unit_amount: 8000000000000000 service_id: register_reset_abci service_registry_address: null setup: @@ -115,6 +117,8 @@ models: safe_contract_address: '0x0000000000000000000000000000000000000000' consensus_threshold: null share_tm_config_on_startup: false + slash_cooldown_hours: 3 + slash_threshold_amount: 10000000000000000 sleep_time: 1 tendermint_check_sleep_delay: 3 tendermint_com_url: http://localhost:8080 @@ -122,6 +126,7 @@ models: tendermint_p2p_url: localhost:26656 tendermint_url: http://localhost:26657 tx_timeout: 10.0 + use_slashing: false use_termination: false class_name: Params requests: diff --git a/packages/valory/skills/register_reset_recovery_abci/skill.yaml b/packages/valory/skills/register_reset_recovery_abci/skill.yaml index 42b7fd36ed..82089935cf 100644 --- a/packages/valory/skills/register_reset_recovery_abci/skill.yaml +++ b/packages/valory/skills/register_reset_recovery_abci/skill.yaml @@ -20,14 +20,14 @@ fingerprint: tests/test_dialogues.py: bafybeifna75wlo2zpymsx2oa5ct7uzujgo6ahnvd5yhzvnn6ekoxrgeaei tests/test_handlers.py: bafybeichmiuqpbxog66ma5kiwlvns6jlbe74vyotq3s75lkvs3g44cruvq tests/test_models.py: bafybeiepyi7jgllfbnpfu6zoy3noha3usukpxiiavcdi272q6z2acqjphq - tests/test_rounds.py: bafybeibhpcmhor6nuqrgrwkr3s6zz3ks42nxdbabwkmbvu7xq3i4uswvbu + tests/test_rounds.py: bafybeihiwbc63zozxrm5ewlqsxrclgnpsw66lyof5o5lmqgswdvhf5mova fingerprint_ignore_patterns: [] connections: [] contracts: [] protocols: [] skills: -- valory/abstract_round_abci:0.1.0:bafybeigiolzp3i6b3wwuau3yv2h5udqape3i7of73mlm2d6ud22irlkbme -- valory/registration_abci:0.1.0:bafybeigjzfdhhu6ody2qo5v2xjobafujnodklia4zw6bkkhahxtjfo3wby +- valory/abstract_round_abci:0.1.0:bafybeicrzndcdbue34yxwwb4hmmdhgzw4owcdcdag3ifj6thpx5wie3dp4 +- valory/registration_abci:0.1.0:bafybeihjlapvviakobxg7aa5qubgqoz6xurlhu7xxtnrg5ah3ag2qj626i behaviours: main: args: {} @@ -97,6 +97,7 @@ models: version: {} voting_power: '10' keeper_timeout: 30.0 + light_slash_unit_amount: 5000000000000000 max_attempts: 10 max_healthcheck: 120 on_chain_service_id: null @@ -107,6 +108,7 @@ models: retry_attempts: 400 retry_timeout: 3 round_timeout_seconds: 15.0 + serious_slash_unit_amount: 8000000000000000 service_id: register_reset_recovery_abci service_registry_address: null setup: @@ -115,6 +117,8 @@ models: safe_contract_address: '0x0000000000000000000000000000000000000000' consensus_threshold: null share_tm_config_on_startup: true + slash_cooldown_hours: 3 + slash_threshold_amount: 10000000000000000 sleep_time: 1 tendermint_check_sleep_delay: 3 tendermint_com_url: http://localhost:8080 @@ -122,6 +126,7 @@ models: tendermint_p2p_url: localhost:26656 tendermint_url: http://localhost:26657 tx_timeout: 10.0 + use_slashing: false use_termination: false class_name: Params requests: diff --git a/packages/valory/skills/register_reset_recovery_abci/tests/test_rounds.py b/packages/valory/skills/register_reset_recovery_abci/tests/test_rounds.py index a41910b81b..6c5d12425e 100644 --- a/packages/valory/skills/register_reset_recovery_abci/tests/test_rounds.py +++ b/packages/valory/skills/register_reset_recovery_abci/tests/test_rounds.py @@ -20,6 +20,7 @@ """Test the rounds of the skill.""" from copy import deepcopy +from unittest.mock import MagicMock from packages.valory.skills.abstract_round_abci.base import BaseSynchronizedData from packages.valory.skills.abstract_round_abci.test_tools.rounds import ( @@ -53,6 +54,7 @@ def test_run( test_round = RoundCountRound( synchronized_data=deepcopy(self.synchronized_data), + context=MagicMock(), ) payload_data = 1 first_payload, *payloads = [ diff --git a/packages/valory/skills/register_termination_abci/behaviours.py b/packages/valory/skills/register_termination_abci/behaviours.py index 3b42470c0e..694a5e73b4 100644 --- a/packages/valory/skills/register_termination_abci/behaviours.py +++ b/packages/valory/skills/register_termination_abci/behaviours.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- # ------------------------------------------------------------------------------ # -# Copyright 2022 Valory AG +# Copyright 2022-2023 Valory AG # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -51,4 +51,4 @@ class RegisterTerminationAbciAppConsensusBehaviour(AbstractRoundBehaviour): *ResetPauseABCIConsensusBehaviour.behaviours, *TerminationAbciBehaviours.behaviours, } - background_behaviour_cls = BackgroundBehaviour + background_behaviours_cls = {BackgroundBehaviour} # type: ignore diff --git a/packages/valory/skills/register_termination_abci/composition.py b/packages/valory/skills/register_termination_abci/composition.py index 3310211e0e..67337cb417 100644 --- a/packages/valory/skills/register_termination_abci/composition.py +++ b/packages/valory/skills/register_termination_abci/composition.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- # ------------------------------------------------------------------------------ # -# Copyright 2022 Valory AG +# Copyright 2022-2023 Valory AG # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -25,6 +25,7 @@ AbciAppTransitionMapping, chain, ) +from packages.valory.skills.abstract_round_abci.base import BackgroundAppConfig from packages.valory.skills.termination_abci.rounds import ( BackgroundRound, Event, @@ -38,14 +39,16 @@ ResetAndPauseAbci.FinishedResetAndPauseErrorRound: ResetAndPauseAbci.ResetAndPauseRound, } +termination_config = BackgroundAppConfig( + round_cls=BackgroundRound, + start_event=Event.TERMINATE, + abci_app=TerminationAbciApp, +) + RegisterTerminateAbciApp = chain( ( RegistrationAbci.AgentRegistrationAbciApp, ResetAndPauseAbci.ResetPauseAbciApp, ), abci_app_transition_mapping, -).add_termination( - background_round_cls=BackgroundRound, - termination_event=Event.TERMINATE, - termination_abci_app=TerminationAbciApp, -) +).add_background_app(termination_config) diff --git a/packages/valory/skills/register_termination_abci/skill.yaml b/packages/valory/skills/register_termination_abci/skill.yaml index bcceac00f9..1c7b50fb1e 100644 --- a/packages/valory/skills/register_termination_abci/skill.yaml +++ b/packages/valory/skills/register_termination_abci/skill.yaml @@ -8,13 +8,13 @@ aea_version: '>=1.0.0, <2.0.0' fingerprint: README.md: bafybeieyro2eupexnqdu2mjqbyhp7jphn5rij4hvdgty5plij52tsffhs4 __init__.py: bafybeicc7zwcm4vljmtobhmgkqinpjgoztznwhfzkndvnnsrolr6eivmsm - behaviours.py: bafybeicmgb3hz2f6rhnpctcojeesayvmwicvl4mybbseyscdvzr6luepni - composition.py: bafybeiadbacacvh4bshv3butbcomyjyxm45vcguivos5ghtflsrwxzv66y + behaviours.py: bafybeidjhvk6aexwr4oat6bkmxbvh3d6kpqpgpo3blrdiasqahc5xlyt5m + composition.py: bafybeic7kp2wqjyhqgvvcy5y2fgiquikuxfksvnibkorvkafomjcchvqli dialogues.py: bafybeif7uhfjkcz3ryhti6gafqxhvciw4ec5bdshxvq3355tun5ydkzrna handlers.py: bafybeifktnmipajc5wtdfjlb46uqd6owlwlcxdvurabehqvdxkvwxdckum models.py: bafybeiha3uip6slahhuqdiusjeosy3yhr7r6u3wxxhrrhhokaxuczofrsm tests/__init__.py: bafybeid2pb3mfobqtzsadxzris67d4hkmcflqfnzay3y3errmtd7tdtvoe - tests/test_behaviours.py: bafybeiawbfepzyltckutgb3hettltrn5pladutcbzlqnpd3jdu4bixlb3i + tests/test_behaviours.py: bafybeidabcgpnfrbgmvjsoobpkfem4ytloemo7d2fhwguzyakznkjl5hlq tests/test_dialogues.py: bafybeiha37jzqmgtfjl52c52xz7osnu7y2ic2sxdp6wkmdgwlbzqtzz3me tests/test_handlers.py: bafybeidxd375se3fx5gpakpauglsmqom3bbizflpw3k265knyy6fxtckra tests/test_models.py: bafybeif2d4kqt7ettspc6fgbeb5y5cm5632rp7dnjcyzy7zfof2m7z6mzq @@ -23,10 +23,10 @@ connections: [] contracts: [] protocols: [] skills: -- valory/abstract_round_abci:0.1.0:bafybeigiolzp3i6b3wwuau3yv2h5udqape3i7of73mlm2d6ud22irlkbme -- valory/registration_abci:0.1.0:bafybeigjzfdhhu6ody2qo5v2xjobafujnodklia4zw6bkkhahxtjfo3wby -- valory/reset_pause_abci:0.1.0:bafybeieeux3rdlcwgjbdfrluvkhqv26qdparre6pabatietw7juklljil4 -- valory/termination_abci:0.1.0:bafybeifkl4ab6dnvtsaefe56dbzshmp5mozn7exwcaj2a3wjeq7u3hpezm +- valory/abstract_round_abci:0.1.0:bafybeicrzndcdbue34yxwwb4hmmdhgzw4owcdcdag3ifj6thpx5wie3dp4 +- valory/registration_abci:0.1.0:bafybeihjlapvviakobxg7aa5qubgqoz6xurlhu7xxtnrg5ah3ag2qj626i +- valory/reset_pause_abci:0.1.0:bafybeibnwjcjx4lluf4cwb6es5peelu3gm7vrzlieygrzpbjlubxpvbvzy +- valory/termination_abci:0.1.0:bafybeifdtxgldw33kwvsavcituzewwbr6iqfcsgk5qouqfhpwdrivyyyom behaviours: main: args: {} @@ -97,6 +97,7 @@ models: init_fallback_gas: 0 keeper_allowed_retries: 3 keeper_timeout: 30.0 + light_slash_unit_amount: 5000000000000000 max_attempts: 10 max_healthcheck: 120 multisend_address: null @@ -108,14 +109,17 @@ models: retry_attempts: 400 retry_timeout: 3 round_timeout_seconds: 15.0 + serious_slash_unit_amount: 8000000000000000 service_id: register_termination_abci service_registry_address: null setup: all_participants: - '0x0000000000000000000000000000000000000000' - safe_contract_address: '0xD8dE647170163a981bb3Fdb2063583eAcF7D55AC' + safe_contract_address: '0x77b783e911F4398D75908Cc60C7138Bd1eFe35Fd' consensus_threshold: null share_tm_config_on_startup: false + slash_cooldown_hours: 3 + slash_threshold_amount: 10000000000000000 sleep_time: 300 tendermint_check_sleep_delay: 3 tendermint_com_url: http://localhost:8080 @@ -124,6 +128,7 @@ models: tendermint_url: http://localhost:26657 termination_sleep: 900 tx_timeout: 10.0 + use_slashing: false use_termination: false validate_timeout: 1205 class_name: Params diff --git a/packages/valory/skills/register_termination_abci/tests/test_behaviours.py b/packages/valory/skills/register_termination_abci/tests/test_behaviours.py index 0231fe68ac..37c3688ebc 100644 --- a/packages/valory/skills/register_termination_abci/tests/test_behaviours.py +++ b/packages/valory/skills/register_termination_abci/tests/test_behaviours.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- # ------------------------------------------------------------------------------ # -# Copyright 2022 Valory AG +# Copyright 2022-2023 Valory AG # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -62,4 +62,4 @@ def test_RegisterSafeTerminationAbciAppConsensusBehaviour() -> None: *ResetPauseABCIConsensusBehaviour.behaviours, *TerminationAbciBehaviours.behaviours, } - assert behaviour.background_behaviour_cls == BackgroundBehaviour + assert behaviour.background_behaviours_cls == {BackgroundBehaviour} diff --git a/packages/valory/skills/registration_abci/behaviours.py b/packages/valory/skills/registration_abci/behaviours.py index 681ac59d90..5cbf7188a5 100644 --- a/packages/valory/skills/registration_abci/behaviours.py +++ b/packages/valory/skills/registration_abci/behaviours.py @@ -17,7 +17,8 @@ # # ------------------------------------------------------------------------------ -"""This module contains the behaviours for the 'abci' skill.""" +"""This module contains the behaviours for the 'registration_abci' skill.""" + import datetime import json from abc import ABC @@ -165,26 +166,30 @@ def is_correct_contract( ) -> Generator[None, None, bool]: """Contract deployment verification.""" - log_message = self.LogMessages.request_verification - self.context.logger.info(f"{log_message}") + self.context.logger.info(self.LogMessages.request_verification) performative = ContractApiMessage.Performative.GET_STATE - contract_api_response = yield from self.get_contract_api_response( - performative=performative, # type: ignore + kwargs = dict( + performative=performative, contract_address=service_registry_address, contract_id=str(ServiceRegistryContract.contract_id), contract_callable="verify_contract", ) + contract_api_response = yield from self.get_contract_api_response(**kwargs) # type: ignore if ( contract_api_response.performative is not ContractApiMessage.Performative.STATE ): - log_message = self.LogMessages.failed_verification - self.context.logger.info(f"{log_message}") - return False - log_message = self.LogMessages.response_verification - self.context.logger.info(f"{log_message}: {contract_api_response}") - return cast(bool, contract_api_response.state.body["verified"]) + verified = False + log_method = self.context.logger.error + log_message = f"{self.LogMessages.failed_verification} ({kwargs}): {contract_api_response}" + else: + verified = cast(bool, contract_api_response.state.body["verified"]) + log_method = self.context.logger.info + log_message = f"{self.LogMessages.response_verification}: {verified}" + + log_method(log_message) + return verified def get_agent_instances( self, service_registry_address: str, on_chain_service_id: int @@ -205,10 +210,9 @@ def get_agent_instances( contract_api_response = yield from self.get_contract_api_response(**kwargs) # type: ignore if contract_api_response.performative != ContractApiMessage.Performative.STATE: log_message = self.LogMessages.failed_service_info - self.context.logger.info( + self.context.logger.error( f"{log_message} ({kwargs}): {contract_api_response}" ) - self.context.logger.info(log_message) return {} log_message = self.LogMessages.response_service_info @@ -221,7 +225,7 @@ def get_addresses(self) -> Generator: # pylint: disable=too-many-return-stateme service_registry_address = self.params.service_registry_address if service_registry_address is None: log_message = self.LogMessages.no_contract_address.value - self.context.logger.info(log_message) + self.context.logger.error(log_message) return False correctly_deployed = yield from self.is_correct_contract( @@ -233,7 +237,7 @@ def get_addresses(self) -> Generator: # pylint: disable=too-many-return-stateme on_chain_service_id = self.params.on_chain_service_id if on_chain_service_id is None: log_message = self.LogMessages.no_on_chain_service_id.value - self.context.logger.info(log_message) + self.context.logger.error(log_message) return False service_info = yield from self.get_agent_instances( @@ -245,13 +249,13 @@ def get_addresses(self) -> Generator: # pylint: disable=too-many-return-stateme registered_addresses = set(service_info["agentInstances"]) if not registered_addresses: log_message = self.LogMessages.no_agents_registered.value - self.context.logger.info(f"{log_message}: {service_info}") + self.context.logger.error(f"{log_message}: {service_info}") return False my_address = self.context.agent_address if my_address not in registered_addresses: log_message = f"{self.LogMessages.self_not_registered} ({my_address})" - self.context.logger.info(f"{log_message}: {registered_addresses}") + self.context.logger.error(f"{log_message}: {registered_addresses}") return False # put service info in the shared state for p2p message handler @@ -311,6 +315,11 @@ def request_tendermint_info(self) -> Generator[None, None, bool]: if all(self.initial_tm_configs.values()): log_message = self.LogMessages.collection_complete self.context.logger.info(f"{log_message}: {self.initial_tm_configs}") + validator_to_agent = { + config["address"]: agent + for agent, config in self.initial_tm_configs.items() + } + self.context.state.setup_slashing(validator_to_agent) self.collection_complete = True return self.collection_complete diff --git a/packages/valory/skills/registration_abci/rounds.py b/packages/valory/skills/registration_abci/rounds.py index c1fe21b688..bc98559768 100644 --- a/packages/valory/skills/registration_abci/rounds.py +++ b/packages/valory/skills/registration_abci/rounds.py @@ -18,6 +18,7 @@ # ------------------------------------------------------------------------------ """This module contains the data classes for common apps ABCI application.""" + from enum import Enum from typing import Dict, Optional, Set, Tuple @@ -29,6 +30,7 @@ CollectSameUntilAllRound, CollectSameUntilThresholdRound, DegenerateRound, + SlashingNotConfiguredError, get_name, ) from packages.valory.skills.registration_abci.payloads import RegistrationPayload @@ -61,7 +63,14 @@ def end_block(self) -> Optional[Tuple[BaseSynchronizedData, Event]]: if not self.collection_threshold_reached: return None - self.synchronized_data.db.sync(self.common_payload) + try: + _ = self.context.state.round_sequence.offence_status + except SlashingNotConfiguredError: + self.context.logger.warning("Slashing has not been enabled!") + else: + self.context.state.round_sequence.enable_slashing() + + self.context.state.round_sequence.sync_db_and_slashing(self.common_payload) synchronized_data = self.synchronized_data.update( participants=tuple(sorted(self.collection)), @@ -97,7 +106,6 @@ def end_block(self) -> Optional[Tuple[BaseSynchronizedData, Event]]: > self.required_block_confirmations # we also wait here as it gives more (available) agents time to join ): self.synchronized_data.db.sync(self.most_voted_payload) - synchronized_data = self.synchronized_data.update( participants=tuple(sorted(self.collection)), synchronized_data_class=self.synchronized_data_class, diff --git a/packages/valory/skills/registration_abci/skill.yaml b/packages/valory/skills/registration_abci/skill.yaml index d0278fdd59..6b191b82e9 100644 --- a/packages/valory/skills/registration_abci/skill.yaml +++ b/packages/valory/skills/registration_abci/skill.yaml @@ -8,31 +8,31 @@ aea_version: '>=1.0.0, <2.0.0' fingerprint: README.md: bafybeieztbubb6yn5umyt5ulknvb2xxppz5ecxaosxqsaejnrcrrwfu2ji __init__.py: bafybeigqj2uodavhrygpqn6iah3ljp53z54c5fxyh5ykgkxuhh5lof6pda - behaviours.py: bafybeieqzn22qx52cqdaqflnf254b4nfshtvl54wtaheyvvnjjp5t3haau + behaviours.py: bafybeibpqaw2lhkbjuc7z4x4tvg2aafdbo3d6uwocifkz23ou7myxfbtpq dialogues.py: bafybeicm4bqedlyytfo4icqqbyolo36j2hk7pqh32d3zc5yqg75bt4demm fsm_specification.yaml: bafybeicx5eutgr4lin7mhwr73xhanuzwdmps7pfoy5f2k7gfxmuec4qbyu handlers.py: bafybeifby6yecei2d7jvxbqrc3tpyemb7xdb4ood2kny5dqja26qnxrf24 models.py: bafybeifkfjsfkjy2x32cbuoewxujfgpcl3wk3fji6kq27ofr2zcfe7l5oe payloads.py: bafybeiacrixfazch2a5ydj7jfk2pnvlxwkygqlwzkfmdeldrj4fqgwyyzm - rounds.py: bafybeicaewfjtvn4tg3te2glocojmd2gzqkjznv2ruyeev22yrw6ed3wu4 + rounds.py: bafybeife3tf3o2xh2paxr62vml5vbuavamstsjkspdr7v3n5psbf4vwp44 tests/__init__.py: bafybeiab2s4vkmbz5bc4wggcclapdbp65bosv4en5zaazk5dwmldojpqja - tests/test_behaviours.py: bafybeiffgw2msg466lrtebl6cqa3736iuis2juf33a6awj7wzrcn5yxi6u + tests/test_behaviours.py: bafybeicwlo3y44sf7gzkyzfuzhwqkax4hln3oforbcvy4uitlgleft3cge tests/test_dialogues.py: bafybeibeqnpzuzgcfb6yz76htslwsbbpenihswbp7j3qdyq42yswjq25l4 tests/test_handlers.py: bafybeifpnwaktxckbvclklo6flkm5zqs7apmb33ffs4jrmunoykjbl5lni tests/test_models.py: bafybeiewxl7nio5av2aukql2u7hlhodzdvjjneleba32abr42xeirrycb4 tests/test_payloads.py: bafybeifik6ek75ughyd4y6t2lchlmjadkzbrz4hsb332k6ul4pwhlo2oga - tests/test_rounds.py: bafybeiefwk4quzkdn7m43rlahdhoe53xtzm4itlznjh26vdt5567oblgdm + tests/test_rounds.py: bafybeidk4d3w5csj6ka7mcq3ikjmv2yccbpwxhp27ujvd7huag3zl5vu2m fingerprint_ignore_patterns: [] connections: -- valory/p2p_libp2p_client:0.1.0:bafybeidwcobzb7ut3efegoedad7jfckvt2n6prcmd4g7xnkm6hp6aafrva +- valory/p2p_libp2p_client:0.1.0:bafybeihge56dn3xep2dzomu7rtvbgo4uc2qqh7ljl3fubqdi2lq44gs5lq contracts: -- valory/service_registry:0.1.0:bafybeiatzikdgcjteti6xeid4bvofszuavxb4fnczx33lcsvlaui4wpwua +- valory/service_registry:0.1.0:bafybeieeuruq7dp4b6souetv5ce7wlm52pw7vyrxuhqa7kuy5m3rwwxks4 protocols: -- valory/contract_api:1.0.0:bafybeidv6wxpjyb2sdyibnmmum45et4zcla6tl63bnol6ztyoqvpl4spmy -- valory/http:1.0.0:bafybeifyoio7nlh5zzyn5yz7krkou56l22to3cwg7gw5v5o3vxwklibhty -- valory/tendermint:0.1.0:bafybeicusvezoqlmyt6iqomcbwaz3xkhk2qf3d56q5zprmj3xdxfy64k54 +- valory/contract_api:1.0.0:bafybeialhbjvwiwcnqq3ysxcyemobcbie7xza66gaofcvla5njezkvhcka +- valory/http:1.0.0:bafybeiejoqgv7finfxo3rcvvovrlj5ccrbgxodjq43uo26ylpowsa3llfe +- valory/tendermint:0.1.0:bafybeig6g6twajlwssfbfp5rlnu5mwzuu5kgak5cs4fich7rlkx6whesnu skills: -- valory/abstract_round_abci:0.1.0:bafybeigiolzp3i6b3wwuau3yv2h5udqape3i7of73mlm2d6ud22irlkbme +- valory/abstract_round_abci:0.1.0:bafybeicrzndcdbue34yxwwb4hmmdhgzw4owcdcdag3ifj6thpx5wie3dp4 behaviours: main: args: {} @@ -102,6 +102,7 @@ models: version: {} voting_power: '10' keeper_timeout: 30.0 + light_slash_unit_amount: 5000000000000000 max_attempts: 10 max_healthcheck: 120 on_chain_service_id: null @@ -112,6 +113,7 @@ models: retry_attempts: 400 retry_timeout: 3 round_timeout_seconds: 30.0 + serious_slash_unit_amount: 8000000000000000 service_id: registration service_registry_address: null setup: @@ -120,6 +122,8 @@ models: safe_contract_address: '0x0000000000000000000000000000000000000000' consensus_threshold: null share_tm_config_on_startup: false + slash_cooldown_hours: 3 + slash_threshold_amount: 10000000000000000 sleep_time: 1 tendermint_check_sleep_delay: 3 tendermint_com_url: http://localhost:8080 @@ -127,6 +131,7 @@ models: tendermint_p2p_url: localhost:26656 tendermint_url: http://localhost:26657 tx_timeout: 10.0 + use_slashing: false use_termination: false class_name: Params requests: diff --git a/packages/valory/skills/registration_abci/tests/test_behaviours.py b/packages/valory/skills/registration_abci/tests/test_behaviours.py index 66fc4bd204..1c19c139e9 100644 --- a/packages/valory/skills/registration_abci/tests/test_behaviours.py +++ b/packages/valory/skills/registration_abci/tests/test_behaviours.py @@ -27,6 +27,7 @@ import logging import time from contextlib import ExitStack, contextmanager +from copy import deepcopy from pathlib import Path from typing import Any, Callable, Dict, Generator, Iterable, List, Optional, cast from unittest import mock @@ -119,9 +120,12 @@ class BaseRegistrationTestBehaviour(RegistrationAbciBaseCase): @pytest.mark.parametrize( "setup_data, expected_initialisation", ( - ({}, '{"0": {}}'), - ({"test": []}, '{"0": {}}'), - ({"test": [], "valid": [1, 2]}, '{"0": {"valid": [1, 2]}}'), + ({}, '{"db_data": {"0": {}}, "slashing_config": ""}'), + ({"test": []}, '{"db_data": {"0": {}}, "slashing_config": ""}'), + ( + {"test": [], "valid": [1, 2]}, + '{"db_data": {"0": {"valid": [1, 2]}}, "slashing_config": ""}', + ), ), ) def test_registration( @@ -315,9 +319,11 @@ def mock_tendermint_request( def mock_get_tendermint_info(self, *addresses: str) -> None: """Mock get Tendermint info""" - for _ in addresses: + for i in addresses: request_kwargs: Dict = dict() - info = json.dumps(DUMMY_VALIDATOR_CONFIG) + config = deepcopy(DUMMY_VALIDATOR_CONFIG) + config["address"] = str(config["address"]) + i + info = json.dumps(config) response_kwargs = dict(info=info) self.mock_tendermint_request(request_kwargs, response_kwargs) # give room to the behaviour to finish sleeping @@ -527,7 +533,19 @@ def test_collection_complete(self, caplog: LogCaptureFixture) -> None: self.mock_is_correct_contract() self.mock_get_agent_instances(*self.agent_instances) self.mock_get_tendermint_info(*self.other_agents) - assert all(map(self.state.initial_tm_configs.get, self.other_agents)) + + initial_tm_configs = self.state.initial_tm_configs + validator_to_agent = ( + self.state.context.state.round_sequence.validator_to_agent + ) + + assert all(map(initial_tm_configs.get, self.other_agents)) + assert tuple(validator_to_agent.keys()) == tuple( + config["address"] for config in initial_tm_configs.values() + ) + assert tuple(validator_to_agent.values()) == tuple( + initial_tm_configs.keys() + ) log_message = self.state.LogMessages.collection_complete assert log_message.value in caplog.text diff --git a/packages/valory/skills/registration_abci/tests/test_rounds.py b/packages/valory/skills/registration_abci/tests/test_rounds.py index 07b73deb5e..d4428005a6 100644 --- a/packages/valory/skills/registration_abci/tests/test_rounds.py +++ b/packages/valory/skills/registration_abci/tests/test_rounds.py @@ -19,16 +19,21 @@ """Test the rounds.py module of the skill.""" -# pylint: skip-file - +import json from typing import Any, Dict, Optional, cast from unittest import mock +from unittest.mock import MagicMock, PropertyMock + +import pytest from packages.valory.skills.abstract_round_abci.base import AbciAppDB from packages.valory.skills.abstract_round_abci.base import ( BaseSynchronizedData as SynchronizedData, ) -from packages.valory.skills.abstract_round_abci.base import CollectSameUntilAllRound +from packages.valory.skills.abstract_round_abci.base import ( + CollectSameUntilAllRound, + SlashingNotConfiguredError, +) from packages.valory.skills.abstract_round_abci.test_tools.rounds import ( BaseCollectSameUntilAllRoundTest, BaseCollectSameUntilThresholdRoundTest, @@ -41,14 +46,19 @@ ) +# pylint: skip-file + + class TestRegistrationStartupRound(BaseCollectSameUntilAllRoundTest): """Test RegistrationStartupRound.""" _synchronized_data_class = SynchronizedData _event_class = RegistrationEvent + @pytest.mark.parametrize("slashing_config", ("", json.dumps({"valid": "config"}))) def test_run_default( self, + slashing_config: str, ) -> None: """Run test.""" @@ -62,8 +72,17 @@ def test_run_default( test_round = RegistrationStartupRound( synchronized_data=self.synchronized_data, + context=MagicMock(), ) + self.synchronized_data.slashing_config = slashing_config + + if not slashing_config: + seq = test_round.context.state.round_sequence + type(seq).offence_status = PropertyMock( + side_effect=SlashingNotConfiguredError + ) + most_voted_payload = self.synchronized_data.db.serialize() round_payloads = { participant: RegistrationPayload( @@ -93,6 +112,15 @@ def test_run_default( ) ) + test_round.context.state.round_sequence.sync_db_and_slashing.assert_called_once_with( + most_voted_payload + ) + + if slashing_config: + test_round.context.state.round_sequence.enable_slashing.assert_called_once() + else: + test_round.context.state.round_sequence.enable_slashing.assert_not_called() + def test_run_default_not_finished( self, ) -> None: @@ -107,6 +135,7 @@ def test_run_default_not_finished( ) test_round = RegistrationStartupRound( synchronized_data=self.synchronized_data, + context=MagicMock(), ) with mock.patch.object( @@ -193,12 +222,15 @@ def test_run_default( ) test_round = RegistrationRound( synchronized_data=self.synchronized_data, + context=MagicMock(), ) + payload_data = self.synchronized_data.db.serialize() + round_payloads = { participant: RegistrationPayload( sender=participant, - initialisation=self.synchronized_data.db.serialize(), + initialisation=payload_data, ) for participant in self.participants } @@ -207,7 +239,7 @@ def test_run_default( test_round=test_round, expected_event=RegistrationEvent.DONE, confirmations=11, - most_voted_payload=self.synchronized_data.db.serialize(), + most_voted_payload=payload_data, round_payloads=round_payloads, ) @@ -237,6 +269,7 @@ def test_run_default_not_finished( ) test_round = RegistrationRound( synchronized_data=self.synchronized_data, + context=MagicMock(), ) self._run_with_round( test_round, @@ -317,6 +350,7 @@ def test_no_majority(self) -> None: test_round = RegistrationRound( synchronized_data=self.synchronized_data, + context=MagicMock(), ) with mock.patch.object(test_round, "is_majority_possible", return_value=False): diff --git a/packages/valory/skills/reset_pause_abci/skill.yaml b/packages/valory/skills/reset_pause_abci/skill.yaml index fb6826bb6e..a86ab42842 100644 --- a/packages/valory/skills/reset_pause_abci/skill.yaml +++ b/packages/valory/skills/reset_pause_abci/skill.yaml @@ -20,13 +20,13 @@ fingerprint: tests/test_dialogues.py: bafybeif7pe7v34cfznzv4htyuevx733ersmk4bqjcgajn2535jmuujdmzm tests/test_handlers.py: bafybeiggog2k65ijtvqwkvjvmaoo6khwgfkeodddzl6u76gcvvongwjawy tests/test_payloads.py: bafybeifj343tlaiasebfgahfxehn4oi74omgah3ju2pze2fefoouid2zdq - tests/test_rounds.py: bafybeig4do5jwnzcpwyklbxh5k7trysl4u2zsagwtf6etqsdtb6yd5s4n4 + tests/test_rounds.py: bafybeifz67lfay4pkz5ipblpfpadl4zmd5riajkv6sdsiby22z24gp3cxa fingerprint_ignore_patterns: [] connections: [] contracts: [] protocols: [] skills: -- valory/abstract_round_abci:0.1.0:bafybeigiolzp3i6b3wwuau3yv2h5udqape3i7of73mlm2d6ud22irlkbme +- valory/abstract_round_abci:0.1.0:bafybeicrzndcdbue34yxwwb4hmmdhgzw4owcdcdag3ifj6thpx5wie3dp4 behaviours: main: args: {} @@ -96,6 +96,7 @@ models: version: {} voting_power: '10' keeper_timeout: 30.0 + light_slash_unit_amount: 5000000000000000 max_attempts: 10 max_healthcheck: 120 on_chain_service_id: null @@ -106,10 +107,13 @@ models: retry_attempts: 400 retry_timeout: 3 round_timeout_seconds: 30.0 + serious_slash_unit_amount: 8000000000000000 service_id: reset_pause_abci service_registry_address: null setup: {} share_tm_config_on_startup: false + slash_cooldown_hours: 3 + slash_threshold_amount: 10000000000000000 sleep_time: 1 tendermint_check_sleep_delay: 3 tendermint_com_url: http://localhost:8080 @@ -117,6 +121,7 @@ models: tendermint_p2p_url: localhost:26656 tendermint_url: http://localhost:26657 tx_timeout: 10.0 + use_slashing: false use_termination: false class_name: Params requests: diff --git a/packages/valory/skills/reset_pause_abci/tests/test_rounds.py b/packages/valory/skills/reset_pause_abci/tests/test_rounds.py index a3e285fb11..adadb778b3 100644 --- a/packages/valory/skills/reset_pause_abci/tests/test_rounds.py +++ b/packages/valory/skills/reset_pause_abci/tests/test_rounds.py @@ -24,6 +24,7 @@ import hashlib import logging # noqa: F401 from typing import Dict, FrozenSet +from unittest.mock import MagicMock from packages.valory.skills.abstract_round_abci.base import ( BaseSynchronizedData as ResetSynchronizedSata, @@ -67,7 +68,10 @@ def test_runs( synchronized_data._db._cross_period_persisted_keys = frozenset( {"most_voted_randomness"} ) - test_round = ResetAndPauseRound(synchronized_data=synchronized_data) + test_round = ResetAndPauseRound( + synchronized_data=synchronized_data, + context=MagicMock(), + ) next_period_count = 1 self._complete_run( self._test_round( @@ -93,7 +97,10 @@ def test_accepting_payloads_from(self) -> None: participants=participants, all_participants=all_participants ) - test_round = ResetAndPauseRound(synchronized_data=synchronized_data) + test_round = ResetAndPauseRound( + synchronized_data=synchronized_data, + context=MagicMock(), + ) assert test_round.accepting_payloads_from != participants assert test_round.accepting_payloads_from == frozenset(all_participants) diff --git a/packages/valory/skills/slashing_abci/__init__.py b/packages/valory/skills/slashing_abci/__init__.py new file mode 100644 index 0000000000..30c18c8f16 --- /dev/null +++ b/packages/valory/skills/slashing_abci/__init__.py @@ -0,0 +1,25 @@ +# -*- coding: utf-8 -*- +# ------------------------------------------------------------------------------ +# +# Copyright 2023 Valory AG +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# ------------------------------------------------------------------------------ + +"""This package contains the background app for the slashing.""" + +from aea.configurations.base import PublicId + + +PUBLIC_ID = PublicId.from_str("valory/slashing_abci:0.1.0") diff --git a/packages/valory/skills/slashing_abci/behaviours.py b/packages/valory/skills/slashing_abci/behaviours.py new file mode 100644 index 0000000000..a934764a92 --- /dev/null +++ b/packages/valory/skills/slashing_abci/behaviours.py @@ -0,0 +1,528 @@ +# -*- coding: utf-8 -*- +# ------------------------------------------------------------------------------ +# +# Copyright 2022-2023 Valory AG +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# ------------------------------------------------------------------------------ + +"""This module contains the slashing background behaviours.""" + +import json +from abc import ABC +from calendar import timegm +from dataclasses import dataclass +from typing import ( + Any, + Callable, + Dict, + FrozenSet, + Generator, + List, + Optional, + Set, + Type, + cast, +) + +from aea.protocols.base import Message + +from packages.valory.contracts.gnosis_safe.contract import GnosisSafeContract +from packages.valory.contracts.service_registry.contract import ServiceRegistryContract +from packages.valory.protocols.contract_api import ContractApiMessage +from packages.valory.skills.abstract_round_abci.base import OffenceStatus, RoundSequence +from packages.valory.skills.abstract_round_abci.behaviour_utils import ( + AsyncBehaviour, + BaseBehaviour, +) +from packages.valory.skills.abstract_round_abci.behaviours import AbstractRoundBehaviour +from packages.valory.skills.abstract_round_abci.utils import inverse +from packages.valory.skills.slashing_abci.composition import SlashingAbciApp +from packages.valory.skills.slashing_abci.models import SharedState +from packages.valory.skills.slashing_abci.payloads import ( + SlashingTxPayload, + StatusResetPayload, +) +from packages.valory.skills.slashing_abci.rounds import ( + SlashingCheckRound, + StatusResetRound, +) +from packages.valory.skills.slashing_abci.rounds import ( + SynchronizedData as SlashingSyncedData, +) +from packages.valory.skills.transaction_settlement_abci.behaviours import ( + TransactionSettlementRoundBehaviour, +) +from packages.valory.skills.transaction_settlement_abci.payload_tools import ( + hash_payload_to_hex, +) +from packages.valory.skills.transaction_settlement_abci.rounds import ( + SynchronizedData as TxSettlementSyncedData, +) +from packages.valory.skills.transaction_settlement_abci.rounds import TX_HASH_LENGTH + + +# setting the safe gas to 0 means that all available gas will be used +# which is what we want in most cases +# more info here: https://safe-docs.dev.gnosisdev.com/safe/docs/contracts_tx_execution/ +_SAFE_GAS = 0 +# hardcoded to 0 because we don't need to send any ETH when slashing +_ETHER_VALUE = 0 + + +class SlashingBaseBehaviour(BaseBehaviour, ABC): + """Represents the base class for the slashing background FSM.""" + + @property + def shared_state(self) -> SharedState: + """Get the round sequence from the shared state.""" + return cast(SharedState, self.context.state) + + @property + def round_sequence(self) -> RoundSequence: + """Get the round sequence from the shared state.""" + return self.shared_state.round_sequence + + @property + def offence_status(self) -> Dict[str, OffenceStatus]: + """Get the offence status from the round sequence.""" + return self.round_sequence.offence_status + + @offence_status.setter + def offence_status(self, status: Dict[str, OffenceStatus]) -> None: + """Set the offence status in the round sequence.""" + self.round_sequence.offence_status = status + + +class SlashingCheckBehaviour(SlashingBaseBehaviour): + """ + A behaviour responsible for checking if there are any slashable events. + + Running concurrently with the other behaviours. + """ + + matching_round = SlashingCheckRound + + def __init__(self, **kwargs: Any) -> None: + """Initialize the slashing check behaviour.""" + super().__init__(**kwargs) + self._slash_amounts: Dict[str, float] = {} + + @property + def synchronized_data(self) -> SlashingSyncedData: + """ + Return the synchronized data. + + Note: we instantiate here, rather than cast, as this runs + concurrently and so the instantiation needs to happen somewhere. + """ + return SlashingSyncedData(db=super().synchronized_data.db) + + @property + def slashable_instances(self) -> List[str]: + """Get the agent instances that are pending to be slashed.""" + return list(self._slash_amounts.keys()) + + @property + def slashable_amounts(self) -> List[float]: + """Get the amounts that are pending to be slashed.""" + return list(self._slash_amounts.values()) + + def is_majority_possible(self) -> bool: + """Checks whether the service has enough participants to reach consensus.""" + return ( + self.synchronized_data.nb_participants + >= self.synchronized_data.consensus_threshold + ) + + def is_slashing_majority_reached(self) -> bool: + """Rely on the round to decide when the majority is reached.""" + return self.synchronized_data.slashing_majority_reached + + def is_round_ended(self, round_id: str) -> Callable[[], bool]: + """ + Get a callable to check whether the current round has ended. + + We consider the background round ended when we have majority on the termination transaction. + Overriden to allow for the behaviour to send transactions at any time. + + :return: the termination majority callable + """ + return self.is_slashing_majority_reached + + def get_callback_request(self) -> Callable[[Message, "BaseBehaviour"], None]: + """Wrapper for callback_request(), overridden to avoid mix-ups with normal (non-background) behaviours.""" + + def callback_request( + message: Message, _current_behaviour: BaseBehaviour + ) -> None: + """ + This method gets called when a response for a prior request is received. + + Overridden to remove the check that checks whether the behaviour that made the request is still active. + The received message gets passed to the behaviour that invoked it, in this case it's always the + background behaviour. + + :param message: the response. + :param _current_behaviour: not used, left in to satisfy the interface. + :return: none + """ + if self.is_stopped: + self.context.logger.info( + "dropping message as behaviour has stopped: %s", message + ) + return + + if self.state != AsyncBehaviour.AsyncState.WAITING_MESSAGE: + self.context.logger.warning( + f"could not send message {message} to {self.behaviour_id}" + ) + return + + self.try_send(message) + + return callback_request + + def _check_offence_status(self) -> None: + """Check the offence status, calculate the slash amount per operator, and assign it to `_slash_amounts`.""" + self._slash_amounts = {} + + for agent, status in self.offence_status.items(): + amount = status.slash_amount( + self.params.light_slash_unit_amount, + self.params.serious_slash_unit_amount, + ) + # If an agent has not been slashed, then it is not included in the timestamps. + # To facilitate the comparison in the subsequent code, + # we assign a timestamp to the negative value of the wait time between slashes(`slash_cooldown_hours`). + # This ensures that the comparison being performed is against 0. + last_slashed_timestamp = self.synchronized_data.slash_timestamps.get( + agent, -self.params.slash_cooldown_hours + ) + last_round_transition_timestamp = timegm( + self.round_sequence.last_round_transition_timestamp.utctimetuple() + ) + + if ( + amount > self.params.slash_threshold_amount + and last_round_transition_timestamp + > last_slashed_timestamp + self.params.slash_cooldown_hours + ): + # Check whether the threshold has been met, essentially bundling up offences. + # Otherwise, we might end up in a situation where the slash tx is more expensive than the slash amount. + # This in itself might be an attack vector, i.e., some malicious agent keeps sending bad payloads, + # so that it drains the funds of the agents. + # Moreover, only store amounts for agents which are not inside the slash wait window, + # i.e., have not been slashed recently. + self._slash_amounts[agent] = amount + + def _get_slash_data(self) -> Generator[None, None, Optional[bytes]]: + """Get the slash tx data encoded.""" + response_msg = yield from self.get_contract_api_response( + performative=ContractApiMessage.Performative.GET_RAW_TRANSACTION, # type: ignore + contract_address=self.params.service_registry_address, + contract_id=str(ServiceRegistryContract.contract_id), + contract_callable="get_slash_data", + agent_instances=self.slashable_instances, + amounts=self.slashable_amounts, + service_id=self.params.on_chain_service_id, + ) + if response_msg.performative != ContractApiMessage.Performative.RAW_TRANSACTION: + self.context.logger.error( + f"Could not get the data for the slash transaction: {response_msg}" + ) + return None + + slash_data = response_msg.raw_transaction.body.get("data", None) + if slash_data is None: + self.context.logger.error( + "Something went wrong while trying to encode the slash data." + ) + + return slash_data + + def _get_safe_tx_hash(self, data: bytes) -> Generator[None, None, Optional[str]]: + """ + Prepares and returns the safe tx hash. + + :param data: the safe tx data. + :return: the tx hash + """ + response_msg = yield from self.get_contract_api_response( + performative=ContractApiMessage.Performative.GET_RAW_TRANSACTION, # type: ignore + contract_address=self.synchronized_data.safe_contract_address, + contract_id=str(GnosisSafeContract.contract_id), + contract_callable="get_raw_safe_transaction_hash", + to_address=self.params.service_registry_address, + value=_ETHER_VALUE, + data=data, + safe_tx_gas=_SAFE_GAS, + ) + + if response_msg.performative != ContractApiMessage.Performative.RAW_TRANSACTION: + self.context.logger.error( + "Couldn't get safe tx hash. Expected response performative " + f"{ContractApiMessage.Performative.RAW_TRANSACTION.value}, received {response_msg}." # type: ignore + ) + return None + + tx_hash = response_msg.raw_transaction.body.get("tx_hash", None) + if tx_hash is None or len(tx_hash) != TX_HASH_LENGTH: + self.context.logger.error( + "Something went wrong while trying to get the slash transaction's hash. " + f"Invalid hash {tx_hash!r} was returned." + ) + return None + + # strip "0x" from the response hash + return tx_hash[2:] + + def async_act(self) -> Generator: + """ + Performs the slashing check logic. + + This method is responsible for checking whether there is any slashable event. + When an agent detects a slashable event, it prepares a multisend transaction, + on which the majority of the agents in the service have to reach consensus on. + + :return: None + :yield: None + """ + if not self.is_majority_possible() or self.synchronized_data.slashing_in_flight: + # If the service does not have enough participants to reach consensus, there is no need to run the act. + # Additionally, we verify whether a slashing operation has already been triggered to avoid duplication. + yield from self.sleep(self.params.sleep_time) + return + + if self.params.service_registry_address is None: # pragma: no cover + raise ValueError( + "Service registry address not set, but is required for slashing!" + ) + + self._check_offence_status() + if len(self._slash_amounts) == 0: + # no slashable events are present, so we sleep and try again + yield from self.sleep(self.params.sleep_time) + return + + self.context.logger.info( + f"Slashable events detected for agent instances: {self.slashable_instances}. " + f"Preparing slashing transaction with amounts: {self.slashable_amounts}." + ) + + data = yield from self._get_slash_data() + if data is None: + self.context.logger.error( + "Cannot construct the safe tx without the slash data." + ) + return + + safe_tx_hash = yield from self._get_safe_tx_hash(data) + if safe_tx_hash is None: + self.context.logger.error("Cannot slash without a safe tx hash.") + return + + slashing_tx_hex = hash_payload_to_hex( + safe_tx_hash, + _ETHER_VALUE, + _SAFE_GAS, + str(self.params.service_registry_address), + data, + ) + + slashing_tx_payload = SlashingTxPayload( + self.context.agent_address, slashing_tx_hex + ) + + self.context.logger.info("Successfully prepared slashing tx payload.") + yield from self.send_a2a_transaction(slashing_tx_payload) + yield from self.wait_for_condition(self.is_slashing_majority_reached) + + +@dataclass +class OperatorSlashedEventLog: + """The logs' structure of an operator slashed event.""" + + amount: int + operator: str + serviceId: int + + +@dataclass +class OperatorSlashedInfo: + """The slash receipt's information after being parsed.""" + + slash_timestamp: int + events: List[OperatorSlashedEventLog] + + def __post_init__(self) -> None: + """Post initialization process for the events.""" + if all(isinstance(event, dict) for event in self.events): + events = cast(dict, self.events) + self.events = [OperatorSlashedEventLog(**event) for event in events] + + +class StatusResetBehaviour(SlashingBaseBehaviour): + """Behaviour that runs after a slash tx has been verified.""" + + matching_round = StatusResetRound + + @property + def slashing_synced_data(self) -> SlashingSyncedData: + """Return the synchronized data.""" + return cast(SlashingSyncedData, self.shared_state.synchronized_data) + + @property + def tx_settlement_synced_data(self) -> TxSettlementSyncedData: + """Return the synchronized data.""" + return TxSettlementSyncedData(db=super().synchronized_data.db) + + def _process_slash_receipt( + self, slash_tx_hash: str + ) -> Generator[None, None, Optional[OperatorSlashedInfo]]: + """Process the slash tx' s receipt.""" + response_msg = yield from self.get_contract_api_response( + performative=ContractApiMessage.Performative.GET_RAW_TRANSACTION, # type: ignore + contract_address=self.params.service_registry_address, + contract_id=str(ServiceRegistryContract.contract_id), + contract_callable="process_slash_receipt", + tx_hash=slash_tx_hash, + ) + + if response_msg.performative != ContractApiMessage.Performative.RAW_TRANSACTION: + self.context.logger.error( + "Couldn't process slashing transaction's receipt. Expected response performative " + f"{ContractApiMessage.Performative.RAW_TRANSACTION.value}, received {response_msg}." # type: ignore + ) + return None + + if response_msg.raw_transaction.body is None: # pragma: no cover + # error is logged in the contract + return None + + return OperatorSlashedInfo(**response_msg.raw_transaction.body) + + def _get_instances_mapping( + self, + agent_instances: FrozenSet[str], + ) -> Generator[None, None, Optional[Dict[str, str]]]: + """ + Retrieve a mapping of the given agent instances to their operators. + + Please keep in mind that this method performs a call for each agent instance. + + :param agent_instances: the agent instances to be mapped. + :return: a mapping of the given agent instances to their operators. + """ + # Ideally, `mapOperatorAndServiceIdAgentInstances` should be used instead of `mapAgentInstanceOperators`, + # so that we have operators mapped to lists of agent instances for the given service id + response_msg = yield from self.get_contract_api_response( + performative=ContractApiMessage.Performative.GET_RAW_TRANSACTION, # type: ignore + contract_address=self.params.service_registry_address, + contract_id=str(ServiceRegistryContract.contract_id), + contract_callable="get_operators_mapping", + agent_instances=agent_instances, + ) + + if response_msg.performative != ContractApiMessage.Performative.RAW_TRANSACTION: + self.context.logger.error( + "Couldn't get operators mapping. Expected response performative " + f"{ContractApiMessage.Performative.RAW_TRANSACTION.value}, received {response_msg}." # type: ignore + ) + return None + + return response_msg.raw_transaction.body + + def async_act(self) -> Generator: + """ + Performs the slash result check and the status reset logic. + + This behaviour is responsible for checking the `OperatorSlashed` event + to determine whether the slashing tx was successful. + If that is the case, it proceeds with resetting the offence status of the slashed agents. + """ + # the `OperatorSlashed` event returns the operators and not the agent instances, so we will need a mapping + operators_mapping = self.slashing_synced_data.operators_mapping + if operators_mapping is None: + instances_mapping = yield from self._get_instances_mapping( + self.slashing_synced_data.all_participants + ) + if instances_mapping is None: + self.context.logger.error( + f"Cannot continue without the agents to operators mapping. " + f"Retrying in {self.params.sleep_time} seconds." + ) + yield from self.sleep(self.params.sleep_time) + return + # as also mentioned in `_get_instances_mapping`, + # it would be better if `mapOperatorAndServiceIdAgentInstances` was used, + # because getting the inverse here would not be necessary + # in any case, we need to sort the mapping, + # as the order in which they are received from the contract is not guaranteed, + # and we need its content to be deterministic as it is later passed via the payload + operators_mapping = inverse(dict(sorted(instances_mapping.items()))) + + # check `OperatorSlashed` event to see which agents were slashed and if everything went as expected + slash_info = yield from self._process_slash_receipt( + self.tx_settlement_synced_data.final_tx_hash + ) + if slash_info is None: + # This signifies that we will continue retrying until either we succeed or the round times out. + # However, this approach carries the risk of getting trapped in a loop! + # + # One potential solution could involve introducing a counter to track the number of retries. + # If the counter would surpass a predefined threshold, we would then proceed to reset the offences + # providing a mechanism to prevent an indefinite loop. + self.context.logger.error( + "Something unexpected happened while checking the slashing operation's result! " + f"Retrying in {self.params.sleep_time} seconds." + ) + yield from self.sleep(self.params.sleep_time) + return + + agent_to_timestamp = { + agent_instance: slash_info.slash_timestamp + for event in slash_info.events + for agent_instance in operators_mapping[event.operator] + } + self.context.logger.info( + f"A slashing operation has been performed for the operator(s) of agents {list(agent_to_timestamp.keys())}." + ) + self.context.logger.info("Resetting status for the slashed agents.") + self.offence_status = { + agent: OffenceStatus() for agent in agent_to_timestamp.keys() + } + self.context.logger.info("Successfully reset status for the slashed agents.") + + status_reset_payload = StatusResetPayload( + self.context.agent_address, + json.dumps(operators_mapping, sort_keys=True), + json.dumps(agent_to_timestamp, sort_keys=True), + ) + + yield from self.send_a2a_transaction(status_reset_payload) + yield from self.wait_until_round_end() + self.set_done() + + +class SlashingAbciBehaviours(AbstractRoundBehaviour): + """This class defines the behaviours required for slashing.""" + + initial_behaviour_cls = TransactionSettlementRoundBehaviour.initial_behaviour_cls + abci_app_cls = SlashingAbciApp + behaviours: Set[Type[BaseBehaviour]] = { + SlashingCheckBehaviour, # type: ignore + StatusResetBehaviour, # type: ignore + *TransactionSettlementRoundBehaviour.behaviours, + } diff --git a/packages/valory/skills/slashing_abci/composition.py b/packages/valory/skills/slashing_abci/composition.py new file mode 100644 index 0000000000..80d095b73c --- /dev/null +++ b/packages/valory/skills/slashing_abci/composition.py @@ -0,0 +1,52 @@ +# -*- coding: utf-8 -*- +# ------------------------------------------------------------------------------ +# +# Copyright 2022-2023 Valory AG +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# ------------------------------------------------------------------------------ + +"""This module contains the slashing background app composition.""" + +from packages.valory.skills.abstract_round_abci.abci_app_chain import ( + AbciAppTransitionMapping, + chain, +) +from packages.valory.skills.slashing_abci.rounds import ( + Event, + PostSlashingTxAbciApp, + SlashingCheckRound, +) +from packages.valory.skills.transaction_settlement_abci.rounds import ( + FailedRound, + FinishedTransactionSubmissionRound, + TransactionSubmissionAbciApp, +) + + +slashing_transition_function: AbciAppTransitionMapping = { + FinishedTransactionSubmissionRound: PostSlashingTxAbciApp.initial_round_cls, + FailedRound: TransactionSubmissionAbciApp.initial_round_cls, +} +SlashingAbciApp = chain( + ( + TransactionSubmissionAbciApp, + PostSlashingTxAbciApp, + ), + slashing_transition_function, +) + +SlashingAbciApp.transition_function[SlashingCheckRound] = { + Event.SLASH_START: TransactionSubmissionAbciApp.initial_round_cls, +} diff --git a/packages/valory/skills/slashing_abci/dialogues.py b/packages/valory/skills/slashing_abci/dialogues.py new file mode 100644 index 0000000000..e985dc8659 --- /dev/null +++ b/packages/valory/skills/slashing_abci/dialogues.py @@ -0,0 +1,91 @@ +# -*- coding: utf-8 -*- +# ------------------------------------------------------------------------------ +# +# Copyright 2023 Valory AG +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# ------------------------------------------------------------------------------ + +"""This module contains the classes required for dialogue management.""" + +from packages.valory.skills.abstract_round_abci.dialogues import ( + AbciDialogue as BaseAbciDialogue, +) +from packages.valory.skills.abstract_round_abci.dialogues import ( + AbciDialogues as BaseAbciDialogues, +) +from packages.valory.skills.abstract_round_abci.dialogues import ( + ContractApiDialogue as BaseContractApiDialogue, +) +from packages.valory.skills.abstract_round_abci.dialogues import ( + ContractApiDialogues as BaseContractApiDialogues, +) +from packages.valory.skills.abstract_round_abci.dialogues import ( + HttpDialogue as BaseHttpDialogue, +) +from packages.valory.skills.abstract_round_abci.dialogues import ( + HttpDialogues as BaseHttpDialogues, +) +from packages.valory.skills.abstract_round_abci.dialogues import ( + IpfsDialogue as BaseIpfsDialogue, +) +from packages.valory.skills.abstract_round_abci.dialogues import ( + IpfsDialogues as BaseIpfsDialogues, +) +from packages.valory.skills.abstract_round_abci.dialogues import ( + LedgerApiDialogue as BaseLedgerApiDialogue, +) +from packages.valory.skills.abstract_round_abci.dialogues import ( + LedgerApiDialogues as BaseLedgerApiDialogues, +) +from packages.valory.skills.abstract_round_abci.dialogues import ( + SigningDialogue as BaseSigningDialogue, +) +from packages.valory.skills.abstract_round_abci.dialogues import ( + SigningDialogues as BaseSigningDialogues, +) +from packages.valory.skills.abstract_round_abci.dialogues import ( + TendermintDialogue as BaseTendermintDialogue, +) +from packages.valory.skills.abstract_round_abci.dialogues import ( + TendermintDialogues as BaseTendermintDialogues, +) + + +AbciDialogue = BaseAbciDialogue +AbciDialogues = BaseAbciDialogues + + +HttpDialogue = BaseHttpDialogue +HttpDialogues = BaseHttpDialogues + + +SigningDialogue = BaseSigningDialogue +SigningDialogues = BaseSigningDialogues + + +LedgerApiDialogue = BaseLedgerApiDialogue +LedgerApiDialogues = BaseLedgerApiDialogues + + +ContractApiDialogue = BaseContractApiDialogue +ContractApiDialogues = BaseContractApiDialogues + + +TendermintDialogue = BaseTendermintDialogue +TendermintDialogues = BaseTendermintDialogues + + +IpfsDialogue = BaseIpfsDialogue +IpfsDialogues = BaseIpfsDialogues diff --git a/packages/valory/skills/slashing_abci/handlers.py b/packages/valory/skills/slashing_abci/handlers.py new file mode 100644 index 0000000000..d252e7ae56 --- /dev/null +++ b/packages/valory/skills/slashing_abci/handlers.py @@ -0,0 +1,51 @@ +# -*- coding: utf-8 -*- +# ------------------------------------------------------------------------------ +# +# Copyright 2023 Valory AG +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# ------------------------------------------------------------------------------ + +"""This module contains the handlers for the slashing skill.""" + +from packages.valory.skills.abstract_round_abci.handlers import ( + ABCIRoundHandler as BaseABCIRoundHandler, +) +from packages.valory.skills.abstract_round_abci.handlers import ( + ContractApiHandler as BaseContractApiHandler, +) +from packages.valory.skills.abstract_round_abci.handlers import ( + HttpHandler as BaseHttpHandler, +) +from packages.valory.skills.abstract_round_abci.handlers import ( + IpfsHandler as BaseIpfsHandler, +) +from packages.valory.skills.abstract_round_abci.handlers import ( + LedgerApiHandler as BaseLedgerApiHandler, +) +from packages.valory.skills.abstract_round_abci.handlers import ( + SigningHandler as BaseSigningHandler, +) +from packages.valory.skills.abstract_round_abci.handlers import ( + TendermintHandler as BaseTendermintHandler, +) + + +ABCIHandler = BaseABCIRoundHandler +HttpHandler = BaseHttpHandler +SigningHandler = BaseSigningHandler +LedgerApiHandler = BaseLedgerApiHandler +ContractApiHandler = BaseContractApiHandler +TendermintHandler = BaseTendermintHandler +IpfsHandler = BaseIpfsHandler diff --git a/packages/valory/skills/slashing_abci/models.py b/packages/valory/skills/slashing_abci/models.py new file mode 100644 index 0000000000..0550fb1c70 --- /dev/null +++ b/packages/valory/skills/slashing_abci/models.py @@ -0,0 +1,45 @@ +# -*- coding: utf-8 -*- +# ------------------------------------------------------------------------------ +# +# Copyright 2023 Valory AG +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# ------------------------------------------------------------------------------ + +"""This module contains the models for the slashing skill.""" + +from packages.valory.skills.abstract_round_abci.models import ( + BenchmarkTool as BaseBenchmarkTool, +) +from packages.valory.skills.abstract_round_abci.models import Requests as BaseRequests +from packages.valory.skills.abstract_round_abci.models import ( + SharedState as BaseSharedState, +) +from packages.valory.skills.slashing_abci.composition import SlashingAbciApp +from packages.valory.skills.transaction_settlement_abci.models import ( + RandomnessApi as TransactionSettlementRandomness, +) +from packages.valory.skills.transaction_settlement_abci.models import TransactionParams + + +class SharedState(BaseSharedState): + """Keeps the current shared state of the skill.""" + + abci_app_cls = SlashingAbciApp + + +SlashingParams = TransactionParams +Requests = BaseRequests +BenchmarkTool = BaseBenchmarkTool +RandomnessApi = TransactionSettlementRandomness diff --git a/packages/valory/skills/hello_world_abci/payloads.py b/packages/valory/skills/slashing_abci/payloads.py similarity index 50% rename from packages/valory/skills/hello_world_abci/payloads.py rename to packages/valory/skills/slashing_abci/payloads.py index 72963a6a67..a0ee762c2a 100644 --- a/packages/valory/skills/hello_world_abci/payloads.py +++ b/packages/valory/skills/slashing_abci/payloads.py @@ -17,42 +17,31 @@ # # ------------------------------------------------------------------------------ -"""This module contains the transaction payloads for the Hello World skill.""" +"""This module contains the transaction payloads for the slashing background skill.""" -from dataclasses import dataclass +from dataclasses import dataclass, field from packages.valory.skills.abstract_round_abci.base import BaseTxPayload @dataclass(frozen=True) -class RegistrationPayload(BaseTxPayload): - """Represent a transaction payload of type 'registration'.""" +class SlashingTxPayload(BaseTxPayload): + """Represent a transaction payload for slashing.""" - -@dataclass(frozen=True) -class CollectRandomnessPayload(BaseTxPayload): - """Represent a transaction payload of type 'randomness'.""" - - round_id: int - randomness: str - - -@dataclass(frozen=True) -class PrintMessagePayload(BaseTxPayload): - """Represent a transaction payload of type 'randomness'.""" - - message: str - - -@dataclass(frozen=True) -class SelectKeeperPayload(BaseTxPayload): - """Represent a transaction payload of type 'select_keeper'.""" - - keeper: str + # normal payload field + tx_hex: str + # these two fields are present in order to simplify the `end_block` method implementation of the corresponding round + in_progress: bool = field(default=True) + sent: bool = field(default=True) @dataclass(frozen=True) -class ResetPayload(BaseTxPayload): - """Represent a transaction payload of type 'reset'.""" - - period_count: int +class StatusResetPayload(BaseTxPayload): + """Represent a transaction payload for resetting the offence status.""" + + # normal payload fields + operators_mapping: str + slash_timestamps: str + # these two fields are present in order to simplify the `end_block` method implementation of the corresponding round + slashing_in_flight: bool = field(default=False) + slash_tx_sent: bool = field(default=False) diff --git a/packages/valory/skills/slashing_abci/rounds.py b/packages/valory/skills/slashing_abci/rounds.py new file mode 100644 index 0000000000..1db1da5b95 --- /dev/null +++ b/packages/valory/skills/slashing_abci/rounds.py @@ -0,0 +1,246 @@ +# -*- coding: utf-8 -*- +# ------------------------------------------------------------------------------ +# +# Copyright 2022-2023 Valory AG +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# ------------------------------------------------------------------------------ + +"""This module contains the slashing rounds.""" + +import json +from enum import Enum +from typing import Dict, List, Optional, Set, Tuple, cast + +from packages.valory.skills.abstract_round_abci.base import ( + ABCIAppInternalError, + AbciApp, + AppState, + BaseSynchronizedData, + BaseTxPayload, + CollectSameUntilThresholdRound, + CollectionRound, + DeserializedCollection, + TransactionNotValidError, + get_name, +) +from packages.valory.skills.slashing_abci.payloads import ( + SlashingTxPayload, + StatusResetPayload, +) +from packages.valory.skills.transaction_settlement_abci.rounds import ( + SynchronizedData as TxSettlementSyncedData, +) + + +class Event(Enum): + """Defines the round events.""" + + SLASH_START = "slash_start" + SLASH_END = "slash_end" + NO_MAJORITY = "no_majority" + ROUND_TIMEOUT = "round_timeout" + NONE = "none" + + +class SynchronizedData(BaseSynchronizedData): + """ + Class to represent the synchronized data. + + This data is replicated by the tendermint application. + """ + + @property + def slashing_bg_init(self) -> bool: + """Get if the slashing background round has been initialized.""" + return bool(self.db.get("slashing_bg_init", False)) + + @property + def slashing_in_flight(self) -> bool: + """Get if there is a slashing operation in progress.""" + return bool(self.db.get("slashing_in_flight", False)) + + @property + def slashing_majority_reached(self) -> bool: + """Get if the slashing majority has been reached.""" + return bool(self.db.get("slashing_majority_reached", False)) + + @property + def operators_mapping(self) -> Optional[Dict[str, List[str]]]: + """Get a mapping of the operators mapped to their agent instances.""" + mapping = self.db.get("operators_mapping", None) + + if mapping is None: + return None + + return json.loads(mapping) + + @property + def slash_timestamps(self) -> Dict[str, int]: + """Get the timestamp in which each agent instance was slashed at.""" + timestamps = str(self.db.get("slash_timestamps", "")) + + if timestamps == "": + return {} + + return json.loads(timestamps) + + @property + def participant_to_offence_reset( + self, + ) -> DeserializedCollection: # pragma: no cover + """The participants mapped to the status reset payloads.""" + serialized = self.db.get_strict("participant_to_randomness") + deserialized = CollectionRound.deserialize_collection(serialized) + return cast(DeserializedCollection, deserialized) + + +class SlashingCheckRound(CollectSameUntilThresholdRound): + """Defines the slashing check background round, which runs concurrently with other rounds to send the slash tx.""" + + payload_class = SlashingTxPayload + synchronized_data_class = SynchronizedData + selection_key = ( + get_name(TxSettlementSyncedData.most_voted_tx_hash), + get_name(SynchronizedData.slashing_in_flight), + get_name(SynchronizedData.slashing_majority_reached), + ) + + def process_payload(self, payload: BaseTxPayload) -> None: + """Process payload.""" + # for background round payloads, we don't need to check the round_count, as round_count is irrelevant for the + # background since it's running concurrently in the background. + sender = payload.sender + if sender not in self.accepting_payloads_from: + raise ABCIAppInternalError( + f"{sender} not in list of participants: {sorted(self.accepting_payloads_from)}" + ) + + if sender in self.collection: + raise ABCIAppInternalError( + f"sender {sender} has already sent value for round: {self.round_id}" + ) + + self.collection[sender] = payload + + def check_payload(self, payload: BaseTxPayload) -> None: + """Check Payload""" + # NOTE: the TransactionNotValidError is intercepted in ABCIRoundHandler.deliver_tx + # which means it will be logged instead of raised + # for background round payloads, we don't need to check the round_count, as round_count is irrelevant for the + # background since it's running concurrently in the background. + sender_in_participant_set = payload.sender in self.accepting_payloads_from + if not sender_in_participant_set: + raise TransactionNotValidError( + f"{payload.sender} not in list of participants: {sorted(self.accepting_payloads_from)}" + ) + + if payload.sender in self.collection: + raise TransactionNotValidError( + f"sender {payload.sender} has already sent value for round: {self.round_id}" + ) + + def end_block(self) -> Optional[Tuple[BaseSynchronizedData, Event]]: + """Process the end of the block.""" + synced_data = SynchronizedData(db=self.synchronized_data.db) + if not synced_data.slashing_bg_init: + # we set the cross-period values because the period will most probably be increased + # before this background round ever returns a `SLASH_START` event. + # if this happens, and we do not set them here, then the db creation for the new period will fail + # because the values are in the cross-period persisted keys. + self.synchronized_data.update( + synchronized_data_class=self.synchronized_data_class, + slashing_bg_init=True, + operators_mapping=None, + slash_timestamps="", + slashing_in_flight=synced_data.slashing_in_flight, + slashing_majority_reached=synced_data.slashing_majority_reached, + ) + + if not self.threshold_reached or synced_data.slashing_in_flight: + return None + + majority_data = dict(zip(self.selection_key, self.most_voted_payload_values)) + state = synced_data.update( + synchronized_data_class=self.synchronized_data_class, + **majority_data, + ) + # we need to reset the collection before returning the slash start event, + # because this round is continuously and concurrently run in the background + self.collection = {} + return state, Event.SLASH_START + + +class StatusResetRound(CollectSameUntilThresholdRound): + """Defines the slashing check background round, which runs after a slash tx has been verified.""" + + payload_class = StatusResetPayload + synchronized_data_class = SynchronizedData + collection_key = get_name(SynchronizedData.participant_to_offence_reset) + selection_key = ( + get_name(SynchronizedData.operators_mapping), + get_name(SynchronizedData.slash_timestamps), + get_name(SynchronizedData.slashing_in_flight), + get_name(SynchronizedData.slashing_majority_reached), + ) + done_event = Event.SLASH_END + no_majority_event = Event.NO_MAJORITY + none_event = Event.NONE + + +class PostSlashingTxAbciApp(AbciApp[Event]): + """PostSlashingTxAbciApp + + Initial round: StatusResetRound + + Initial states: {StatusResetRound} + + Transition states: + 0. StatusResetRound + - slash end: 0. + - no majority: 0. + - round timeout: 0. + - none: 0. + + Final states: {} + + Timeouts: + round timeout: 30.0 + """ + + initial_round_cls = StatusResetRound + initial_states = {StatusResetRound} + transition_function = { + StatusResetRound: { + # the following is not needed, it is added to satisfy the round check. + # the `SLASH_END` event is the end event of the slashing background app, + # which signals the app to return to the main transition function + # for more information, see `BackgroundApp` and `AbciApp` implementation + Event.SLASH_END: StatusResetRound, + Event.NO_MAJORITY: StatusResetRound, + Event.ROUND_TIMEOUT: StatusResetRound, + # none event cannot occur + Event.NONE: StatusResetRound, + }, + } + cross_period_persisted_keys = frozenset( + { + get_name(SynchronizedData.operators_mapping), + get_name(SynchronizedData.slash_timestamps), + get_name(SynchronizedData.slashing_in_flight), + get_name(SynchronizedData.slashing_majority_reached), + } + ) + event_to_timeout: Dict[Event, float] = {Event.ROUND_TIMEOUT: 30.0} + db_pre_conditions: Dict[AppState, Set[str]] = {StatusResetRound: set()} diff --git a/packages/valory/skills/slashing_abci/skill.yaml b/packages/valory/skills/slashing_abci/skill.yaml new file mode 100644 index 0000000000..ee8e8c2db0 --- /dev/null +++ b/packages/valory/skills/slashing_abci/skill.yaml @@ -0,0 +1,153 @@ +name: slashing_abci +author: valory +version: 0.1.0 +type: skill +description: Slashing skill. +license: Apache-2.0 +aea_version: '>=1.0.0, <2.0.0' +fingerprint: + __init__.py: bafybeiaa4imr3kx3j7yi6z5hm2u5jtx5ozlqkmkjktzy4jctyooqakdjca + behaviours.py: bafybeiewsvo22hm7l2yvrltcnmubyplh4xstvh3u2yot6eofqgbaxhlzqm + composition.py: bafybeielasseqc663nstmdkbrvzjcy5kxp7jnv745svousetfyglb235ze + dialogues.py: bafybeigpwuzku3we7axmxeamg7vn656maww6emuztau5pg3ebsoquyfdqm + handlers.py: bafybeihagfgueqadffrmvqwkrjk4vhalhfvsctquay2uiqru2h4vur6j5e + models.py: bafybeifr2eeesjvoo52z5fvnar4j7q3o7etqzq4arqbxn622gvdyfymz4u + payloads.py: bafybeif6hfnib6yrurrju4dtxnccwsnoi2keqp7sr4qas6xegseunygydu + rounds.py: bafybeibiypvjy7f2cs6h33jtu44w3dhgfj6lrvgh6juidgas3n4bxbvc4a + tests/__init__.py: bafybeiesff34nldcxucqzb7fz5bg6awtqxgcafvasecdsh5eutmtahwaeu + tests/test_behaviours.py: bafybeihhzhfmd7jvybvmsuvryajafuqzkjjd7lifxlva6xyl2vo7jeb5yu + tests/test_dialogues.py: bafybeiaipkfzciwtc6emjsi2vatof3tjptxww5cwqymefs57co7f2hb6pe + tests/test_handlers.py: bafybeicbxl2n4ch6p347ksb6dgm2orebrbj26oplfhvkk25l5crspzbvs4 + tests/test_models.py: bafybeifnjo33d2q2hsqcf4bwdk7wcp45amt7idogup24botupdo7u4cuju + tests/test_payloads.py: bafybeifo57bmelwv2rbtzvmk5yfrv6x4rbq6jdlrwpfge62ija5a7zj56m + tests/test_rounds.py: bafybeibxefl7qknfjkclen4tj67dbixol6x7ji74gwhzprwhdi7yn4sc4y +fingerprint_ignore_patterns: [] +connections: [] +contracts: +- valory/gnosis_safe:0.1.0:bafybeiegkl6zrbvlbpwmoziw4hfkocjfqdqphkmpgow7ovsmv7bwa3f4pe +- valory/service_registry:0.1.0:bafybeieeuruq7dp4b6souetv5ce7wlm52pw7vyrxuhqa7kuy5m3rwwxks4 +protocols: +- valory/contract_api:1.0.0:bafybeialhbjvwiwcnqq3ysxcyemobcbie7xza66gaofcvla5njezkvhcka +skills: +- valory/abstract_round_abci:0.1.0:bafybeicrzndcdbue34yxwwb4hmmdhgzw4owcdcdag3ifj6thpx5wie3dp4 +- valory/transaction_settlement_abci:0.1.0:bafybeifpnkwgwpzz6uwrvfgurm26allr6shjfbp7bfbrxwy64sw3nf3fsa +behaviours: + main: + args: {} + class_name: SlashingAbciBehaviours +handlers: + abci: + args: {} + class_name: ABCIHandler + contract_api: + args: {} + class_name: ContractApiHandler + http: + args: {} + class_name: HttpHandler + ipfs: + args: {} + class_name: IpfsHandler + ledger_api: + args: {} + class_name: LedgerApiHandler + signing: + args: {} + class_name: SigningHandler + tendermint: + args: {} + class_name: TendermintHandler +models: + abci_dialogues: + args: {} + class_name: AbciDialogues + benchmark_tool: + args: + log_dir: /logs + class_name: BenchmarkTool + contract_api_dialogues: + args: {} + class_name: ContractApiDialogues + http_dialogues: + args: {} + class_name: HttpDialogues + ipfs_dialogues: + args: {} + class_name: IpfsDialogues + ledger_api_dialogues: + args: {} + class_name: LedgerApiDialogues + params: + args: + cleanup_history_depth: 1 + cleanup_history_depth_current: null + drand_public_key: 868f005eb8e6e4ca0a47c8a77ceaa5309a47978a7c71bc5cce96366b5d7a569937c529eeda66c7293784a9402801af31 + finalize_timeout: 60.0 + genesis_config: + genesis_time: '2022-05-20T16:00:21.735122717Z' + chain_id: chain-c4daS1 + consensus_params: + block: + max_bytes: '22020096' + max_gas: '-1' + time_iota_ms: '1000' + evidence: + max_age_num_blocks: '100000' + max_age_duration: '172800000000000' + max_bytes: '1048576' + validator: + pub_key_types: + - ed25519 + version: {} + voting_power: '10' + history_check_timeout: 1205 + init_fallback_gas: 0 + ipfs_domain_name: null + keeper_allowed_retries: 3 + keeper_timeout: 30.0 + light_slash_unit_amount: 5000000000000000 + max_attempts: 10 + max_healthcheck: 120 + multisend_address: '0xA238CBeb142c10Ef7Ad8442C6D1f9E89e07e7761' + on_chain_service_id: null + request_retry_delay: 1.0 + request_timeout: 10.0 + reset_pause_duration: 10 + reset_tendermint_after: 2 + retry_attempts: 400 + retry_timeout: 3 + round_timeout_seconds: 30.0 + serious_slash_unit_amount: 8000000000000000 + service_id: termination_abci + service_registry_address: '0x48b6af7B12C71f09e2fC8aF4855De4Ff54e775cA' + setup: {} + share_tm_config_on_startup: false + slash_cooldown_hours: 3 + slash_threshold_amount: 10000000000000000 + sleep_time: 1 + tendermint_check_sleep_delay: 3 + tendermint_com_url: http://localhost:8080 + tendermint_max_retries: 5 + tendermint_p2p_url: localhost:26656 + tendermint_url: http://localhost:26657 + termination_sleep: 900 + tx_timeout: 10.0 + use_slashing: false + use_termination: false + validate_timeout: 1205 + class_name: SlashingParams + requests: + args: {} + class_name: Requests + signing_dialogues: + args: {} + class_name: SigningDialogues + state: + args: {} + class_name: SharedState + tendermint_dialogues: + args: {} + class_name: TendermintDialogues +dependencies: + hexbytes: {} +is_abstract: true diff --git a/packages/valory/skills/slashing_abci/tests/__init__.py b/packages/valory/skills/slashing_abci/tests/__init__.py new file mode 100644 index 0000000000..e959d98ca8 --- /dev/null +++ b/packages/valory/skills/slashing_abci/tests/__init__.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# ------------------------------------------------------------------------------ +# +# Copyright 2023 Valory AG +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# ------------------------------------------------------------------------------ + +"""Tests for the slashing background app.""" diff --git a/packages/valory/skills/slashing_abci/tests/test_behaviours.py b/packages/valory/skills/slashing_abci/tests/test_behaviours.py new file mode 100644 index 0000000000..80660290b8 --- /dev/null +++ b/packages/valory/skills/slashing_abci/tests/test_behaviours.py @@ -0,0 +1,506 @@ +# -*- coding: utf-8 -*- +# ------------------------------------------------------------------------------ +# +# Copyright 2023 Valory AG +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# ------------------------------------------------------------------------------ + +"""Tests the behaviours of the slashing.""" + +# pylint: disable=protected-access + +import json +from copy import deepcopy +from dataclasses import dataclass +from datetime import datetime +from pathlib import Path +from typing import Any, Dict, List, Optional, Type, Union, cast +from unittest import mock +from unittest.mock import MagicMock + +import pytest + +from packages.valory.contracts.gnosis_safe.contract import GnosisSafeContract +from packages.valory.contracts.service_registry.contract import ServiceRegistryContract +from packages.valory.protocols.contract_api import ContractApiMessage +from packages.valory.protocols.contract_api.custom_types import RawTransaction +from packages.valory.skills.abstract_round_abci.base import AbciAppDB, OffenceStatus +from packages.valory.skills.abstract_round_abci.behaviour_utils import ( + AsyncBehaviour, + BaseBehaviour, +) +from packages.valory.skills.abstract_round_abci.test_tools.base import ( + FSMBehaviourBaseCase, +) +from packages.valory.skills.abstract_round_abci.utils import inverse +from packages.valory.skills.slashing_abci.behaviours import ( + SlashingAbciBehaviours, + SlashingCheckBehaviour, + StatusResetBehaviour, +) +from packages.valory.skills.slashing_abci.rounds import Event, SynchronizedData +from packages.valory.skills.transaction_settlement_abci.behaviours import ( + TransactionSettlementRoundBehaviour, +) +from packages.valory.skills.transaction_settlement_abci.rounds import TX_HASH_LENGTH + + +STUB_OPERATORS_MAPPING = { + "test_instance_1": "test_operator", + "test_instance_0": "test_operator", +} +DUMMY_SLASH_THRESHOLD = 1 +DUMMY_SLASH_COOLDOWN = 1 + + +class BaseSlashingTest(FSMBehaviourBaseCase): + """Base test case.""" + + path_to_skill = Path(__file__).parents[1] + behaviour: SlashingAbciBehaviours + behaviour_class: Type[BaseBehaviour] = SlashingCheckBehaviour + next_behaviour_class: Type[ + BaseBehaviour + ] = TransactionSettlementRoundBehaviour.initial_behaviour_cls + synchronized_data: SynchronizedData + done_event = Event.SLASH_START + + @property + def current_behaviour( + self, + ) -> Union[BaseBehaviour, SlashingCheckBehaviour, StatusResetBehaviour]: + """Get the current behaviour.""" + return cast( + Union[BaseBehaviour, SlashingCheckBehaviour, StatusResetBehaviour], + self.behaviour.current_behaviour, + ) + + def fast_forward(self, data: Optional[Dict[str, Any]] = None) -> None: + """Fast-forward on initialization""" + + data = data or {} + self.fast_forward_to_behaviour( + self.behaviour, + self.behaviour_class.auto_behaviour_id(), + SynchronizedData(AbciAppDB(setup_data=AbciAppDB.data_to_lists(data))), + ) + assert ( + self.behaviour.current_behaviour is not None + and self.behaviour.current_behaviour.behaviour_id + == self.behaviour_class.auto_behaviour_id() + ) + self.current_behaviour.params.__dict__["_frozen"] = False + self.current_behaviour.params.slash_threshold_amount = DUMMY_SLASH_THRESHOLD + self.current_behaviour.params.slash_cooldown_hours = DUMMY_SLASH_COOLDOWN + self.current_behaviour.params.__dict__["_frozen"] = True + + def complete(self) -> None: + """Complete test""" + self.mock_a2a_transaction() + self.end_round(done_event=self.done_event) + assert ( + self.behaviour.current_behaviour is not None + and self.behaviour.current_behaviour.behaviour_id + == self.next_behaviour_class.auto_behaviour_id() + ) + + +class TestSlashingCheckBehaviour(BaseSlashingTest): + """Tests for `SlashingCheckBehaviour`.""" + + behaviour_class = SlashingCheckBehaviour + + def _mock_get_slash_data( + self, error: bool = False, invalid_data: bool = False + ) -> None: + """Mock a ServiceRegistryContract.get_slash_data() request.""" + if not error: + response_performative = ContractApiMessage.Performative.RAW_TRANSACTION + response_body = {} if invalid_data else {"data": b"slash_data"} + else: + response_performative = ContractApiMessage.Performative.ERROR + response_body = {} + + self.mock_contract_api_request( + contract_id=str(ServiceRegistryContract.contract_id), + request_kwargs=dict( + performative=ContractApiMessage.Performative.GET_RAW_TRANSACTION, + contract_address=self.current_behaviour.params.service_registry_address, + ), + response_kwargs=dict( + performative=response_performative, + raw_transaction=RawTransaction( + ledger_id="ethereum", + body=response_body, + ), + ), + ) + + def _mock_get_safe_tx_hash( + self, + error: bool = False, + invalid_hash: bool = False, + ) -> None: + """Mock a GnosisSafeContract.get_raw_safe_transaction_hash() request.""" + if not error: + response_performative = ContractApiMessage.Performative.RAW_TRANSACTION + response_body = ( + {"tx_hash": "0x"} + if invalid_hash + else {"tx_hash": "0x" + "0" * (TX_HASH_LENGTH - 2)} + ) + else: + response_performative = ContractApiMessage.Performative.ERROR + response_body = {} + + self.mock_contract_api_request( + contract_id=str(GnosisSafeContract.contract_id), + request_kwargs=dict( + performative=ContractApiMessage.Performative.GET_RAW_TRANSACTION, + contract_address=self.current_behaviour.synchronized_data.safe_contract_address, + ), + response_kwargs=dict( + performative=response_performative, + raw_transaction=RawTransaction( + ledger_id="ethereum", + body=response_body, + ), + ), + ) + + @mock.patch.object(AsyncBehaviour, "try_send") + def test_get_callback_request(self, try_send_mock: mock.Mock) -> None: + """Test `get_callback_request` method.""" + self.fast_forward( + data=dict( + slashing_in_flight=False, + all_participants=["a"], + participants=["a"], + consensus_threshold=1, + ) + ) + self.current_behaviour.round_sequence._offence_status = {"a": OffenceStatus()} + self.current_behaviour.round_sequence._last_round_transition_timestamp = ( + datetime(2000, 1, 1) + ) + + # `__stopped` is `True` in the beginning + callback = self.current_behaviour.get_callback_request() + message_mock = MagicMock() + callback(message_mock, MagicMock()) + try_send_mock.assert_not_called() + + # call act wrapper so that `__call_act_first_time()` is triggered, which sets `self.__stopped = False` + # however, state is not `AsyncState.WAITING_MESSAGE` + self.behaviour.act_wrapper() + callback(message_mock, MagicMock()) + try_send_mock.assert_not_called() + + # call `wait_for_message()` which sets `self.__state = self.AsyncState.WAITING_MESSAGE` + wait_gen = self.current_behaviour.wait_for_message() + next(wait_gen) + callback(message_mock, MagicMock()) + try_send_mock.assert_called_once_with(message_mock) + + @pytest.mark.parametrize( + "offence_status, timestamps, last_timestamp, expected_amounts", + ( + ( + {"agent": MagicMock(slash_amount=MagicMock(return_value=0))}, + {"agent": 0}, + datetime(2000, 1, 1), + {}, + ), + ( + { + "agent": MagicMock( + slash_amount=MagicMock(return_value=DUMMY_SLASH_THRESHOLD) + ) + }, + {"agent": 946684800 - DUMMY_SLASH_COOLDOWN}, + datetime(2000, 1, 1), + {}, + ), + ( + { + "agent": MagicMock( + slash_amount=MagicMock(return_value=DUMMY_SLASH_THRESHOLD + 1) + ) + }, + {"agent": 946684800}, + datetime(2000, 1, 1), + {}, + ), + ( + { + "agent": MagicMock( + slash_amount=MagicMock(return_value=DUMMY_SLASH_THRESHOLD + 1) + ) + }, + {"agent": 946684800 - DUMMY_SLASH_COOLDOWN - 1}, + datetime(2000, 1, 1), + {"agent": DUMMY_SLASH_THRESHOLD + 1}, + ), + ), + ) + def test_check_offence_status( + self, + offence_status: Dict[str, MagicMock], + timestamps: Dict[str, int], + last_timestamp: datetime, + expected_amounts: Dict[str, int], + ) -> None: + """Test the `_check_offence_status` method.""" + self.fast_forward(data={"slash_timestamps": json.dumps(timestamps)}) + # repeating this check for the `current_behaviour` here to avoid `mypy` reporting: + # `error: Item "None" of "Optional[BaseBehaviour]" has no attribute "context"` when accessing the context below + assert self.current_behaviour is not None + + self.current_behaviour._slash_amounts = {"agent": "something_random"} + self.current_behaviour.round_sequence._offence_status = offence_status # type: ignore + self.current_behaviour.round_sequence._last_round_transition_timestamp = ( + last_timestamp + ) + + self.current_behaviour._check_offence_status() + assert self.current_behaviour._slash_amounts == expected_amounts + + @dataclass + class SlashingCheckBehaviourTestCase: + """Test case parametrization for the `SlashingCheckBehaviour`.""" + + slashing_in_flight: bool = False + consensus_threshold: int = 1 + num_double_signed: int = 1 + slash_data_error: bool = False + slash_data_invalid: bool = False + safe_tx_error: bool = False + safe_tx_invalid: bool = False + + @property + def all_participants(self) -> List[str]: + """Generate a stub list with participants.""" + return [f"participant{i}" for i in range(self.consensus_threshold)] + + @pytest.mark.parametrize( + "test_case", + ( + SlashingCheckBehaviourTestCase(slashing_in_flight=True), + SlashingCheckBehaviourTestCase(consensus_threshold=2), + SlashingCheckBehaviourTestCase(num_double_signed=0), + SlashingCheckBehaviourTestCase(slash_data_error=True), + SlashingCheckBehaviourTestCase(slash_data_invalid=True), + SlashingCheckBehaviourTestCase(safe_tx_error=True), + SlashingCheckBehaviourTestCase(safe_tx_invalid=True), + SlashingCheckBehaviourTestCase(), + ), + ) + @mock.patch.object(AsyncBehaviour, "sleep") + def test_slashing_check_act( + self, sleep_mock: mock.Mock, test_case: SlashingCheckBehaviourTestCase + ) -> None: + """Test `PendingOffencesBehaviour`'s async act.""" + first_participant = test_case.all_participants[0] + self.fast_forward( + data=dict( + slashing_in_flight=test_case.slashing_in_flight, + all_participants=test_case.all_participants, + participants=[first_participant], + consensus_threshold=test_case.consensus_threshold, + safe_contract_address="test_safe_contract_address", + ) + ) + self.current_behaviour.round_sequence._offence_status = { + first_participant: OffenceStatus() + } + self.current_behaviour.round_sequence._offence_status[ + first_participant + ].num_double_signed += test_case.num_double_signed + self.current_behaviour.round_sequence._last_round_transition_timestamp = ( + datetime(2000, 1, 1) + ) + self.behaviour.act_wrapper() + if test_case.slashing_in_flight or test_case.consensus_threshold == 2: + with pytest.raises(AssertionError): + self._mock_get_slash_data( + test_case.slash_data_error, test_case.slash_data_invalid + ) + return + + if test_case.num_double_signed == 0: + with pytest.raises(AssertionError): + self._mock_get_slash_data( + test_case.slash_data_error, test_case.slash_data_invalid + ) + sleep_mock.assert_called_once_with(self.current_behaviour.params.sleep_time) + return + + self._mock_get_slash_data( + test_case.slash_data_error, test_case.slash_data_invalid + ) + + if test_case.slash_data_error or test_case.slash_data_invalid: + with pytest.raises(AssertionError): + self._mock_get_safe_tx_hash( + test_case.safe_tx_error, test_case.safe_tx_invalid + ) + return + + self._mock_get_safe_tx_hash(test_case.safe_tx_error, test_case.safe_tx_invalid) + + if test_case.safe_tx_error or test_case.safe_tx_invalid: + with pytest.raises(AssertionError): + self.complete() + return + + self.complete() + sleep_mock.assert_not_called() + + +class TestStatusResetBehaviour(BaseSlashingTest): + """Tests for `StatusResetBehaviour`.""" + + behaviour_class = StatusResetBehaviour + next_behaviour_class = StatusResetBehaviour + done_event = Event.SLASH_END + + def _mock_process_slash_receipt( + self, + error: bool = False, + ) -> None: + """Mock a ServiceRegistryContract.process_slash_receipt() request.""" + if not error: + response_performative = ContractApiMessage.Performative.RAW_TRANSACTION + response_body = { + "slash_timestamp": 10, + "events": [{"amount": 2, "operator": "test_operator", "serviceId": 1}], + } + else: + response_performative = ContractApiMessage.Performative.ERROR + response_body = {} + + self.mock_contract_api_request( + contract_id=str(ServiceRegistryContract.contract_id), + request_kwargs=dict( + performative=ContractApiMessage.Performative.GET_RAW_TRANSACTION, + contract_address=self.current_behaviour.params.service_registry_address, + ), + response_kwargs=dict( + performative=response_performative, + raw_transaction=RawTransaction( + ledger_id="ethereum", + body=response_body, + ), + ), + ) + + def _mock_get_instances_mapping( + self, + error: bool = False, + ) -> None: + """Mock a ServiceRegistryContract.get_operators_mapping() request.""" + if not error: + response_performative = ContractApiMessage.Performative.RAW_TRANSACTION + response_body = STUB_OPERATORS_MAPPING + else: + response_performative = ContractApiMessage.Performative.ERROR + response_body = {} + + self.mock_contract_api_request( + contract_id=str(ServiceRegistryContract.contract_id), + request_kwargs=dict( + performative=ContractApiMessage.Performative.GET_RAW_TRANSACTION, + contract_address=self.current_behaviour.params.service_registry_address, + ), + response_kwargs=dict( + performative=response_performative, + raw_transaction=RawTransaction( + ledger_id="ethereum", + body=response_body, + ), + ), + ) + + @dataclass + class StatusResetBehaviourTestCase: + """Test case parametrization for the `StatusResetBehaviour`.""" + + operators_mapping: Optional[str] = None + get_mapping_error: bool = False + process_receipt_error: bool = False + + @pytest.mark.parametrize( + "test_case", + ( + StatusResetBehaviourTestCase(get_mapping_error=True), + StatusResetBehaviourTestCase(process_receipt_error=True), + StatusResetBehaviourTestCase( + operators_mapping=json.dumps( + inverse(dict(sorted(STUB_OPERATORS_MAPPING.items()))) + ) + ), + StatusResetBehaviourTestCase(), + ), + ) + @mock.patch.object(AsyncBehaviour, "sleep") + def test_status_reset_act( + self, sleep_mock: mock.Mock, test_case: StatusResetBehaviourTestCase + ) -> None: + """Test `PendingOffencesBehaviour`'s async act.""" + self.fast_forward( + data=dict( + final_tx_hash="final_tx_hash", + all_participants=["a"], + participants=["a"], + consensus_threshold=1, + operators_mapping=test_case.operators_mapping, + ) + ) + # initialize the offence status with a fake offence + first_instance = list(STUB_OPERATORS_MAPPING.keys())[0] + initial_offence_status = { + instance: OffenceStatus() for instance in STUB_OPERATORS_MAPPING + } + offence_status = deepcopy(initial_offence_status) + offence_status[first_instance].num_double_signed = 1 + self.current_behaviour.round_sequence._offence_status = deepcopy(offence_status) + self.behaviour.act_wrapper() + + if test_case.operators_mapping is None and test_case.get_mapping_error: + self._mock_get_instances_mapping(test_case.get_mapping_error) + sleep_mock.assert_called_once_with(self.current_behaviour.params.sleep_time) + with pytest.raises(AssertionError): + self._mock_process_slash_receipt(test_case.process_receipt_error) + return + + if test_case.operators_mapping is None: + self._mock_get_instances_mapping(test_case.get_mapping_error) + + assert self.current_behaviour.offence_status == offence_status + self._mock_process_slash_receipt(test_case.process_receipt_error) + + if test_case.process_receipt_error: + sleep_mock.assert_called_once_with(self.current_behaviour.params.sleep_time) + with pytest.raises(AssertionError): + self.complete() + return + + assert self.current_behaviour.offence_status == initial_offence_status + # check the order for determinism + assert list(self.current_behaviour.offence_status.keys()) == sorted( + initial_offence_status.keys() + ) + self.complete() + sleep_mock.assert_not_called() diff --git a/packages/valory/skills/slashing_abci/tests/test_dialogues.py b/packages/valory/skills/slashing_abci/tests/test_dialogues.py new file mode 100644 index 0000000000..c1dc0e7b44 --- /dev/null +++ b/packages/valory/skills/slashing_abci/tests/test_dialogues.py @@ -0,0 +1,28 @@ +# -*- coding: utf-8 -*- +# ------------------------------------------------------------------------------ +# +# Copyright 2023 Valory AG +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# ------------------------------------------------------------------------------ +# pylint: disable=unused-import + +"""Test the dialogues.py module of the skill.""" + + +import packages.valory.skills.slashing_abci.dialogues # noqa + + +def test_import() -> None: + """Test that the 'dialogues.py' Python module can be imported.""" diff --git a/packages/valory/skills/slashing_abci/tests/test_handlers.py b/packages/valory/skills/slashing_abci/tests/test_handlers.py new file mode 100644 index 0000000000..7c4eeb2628 --- /dev/null +++ b/packages/valory/skills/slashing_abci/tests/test_handlers.py @@ -0,0 +1,28 @@ +# -*- coding: utf-8 -*- +# ------------------------------------------------------------------------------ +# +# Copyright 2023 Valory AG +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# ------------------------------------------------------------------------------ +# pylint: disable=unused-import + +"""Test the dialogues.py module of the skill.""" + + +import packages.valory.skills.slashing_abci.handlers # noqa + + +def test_import() -> None: + """Test that the 'handlers.py' Python module can be imported.""" diff --git a/packages/valory/skills/hello_world_abci/tests/test_models.py b/packages/valory/skills/slashing_abci/tests/test_models.py similarity index 82% rename from packages/valory/skills/hello_world_abci/tests/test_models.py rename to packages/valory/skills/slashing_abci/tests/test_models.py index fbd98c5822..b542da3272 100644 --- a/packages/valory/skills/hello_world_abci/tests/test_models.py +++ b/packages/valory/skills/slashing_abci/tests/test_models.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- # ------------------------------------------------------------------------------ # -# Copyright 2021-2022 Valory AG +# Copyright 2023 Valory AG # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -19,17 +19,15 @@ """Test the models.py module of the skill.""" -# pylint: skip-file from packages.valory.skills.abstract_round_abci.test_tools.base import DummyContext -from packages.valory.skills.hello_world_abci.models import SharedState +from packages.valory.skills.slashing_abci.models import SharedState -class TestSharedState: +class TestSharedState: # pylint: disable=too-few-public-methods """Test SharedState(Model) class.""" - def test_initialization( - self, - ) -> None: + @staticmethod + def test_initialization() -> None: """Test initialization.""" SharedState(name="", skill_context=DummyContext()) diff --git a/packages/valory/skills/slashing_abci/tests/test_payloads.py b/packages/valory/skills/slashing_abci/tests/test_payloads.py new file mode 100644 index 0000000000..23bf3e17e6 --- /dev/null +++ b/packages/valory/skills/slashing_abci/tests/test_payloads.py @@ -0,0 +1,92 @@ +# -*- coding: utf-8 -*- +# ------------------------------------------------------------------------------ +# +# Copyright 2021-2023 Valory AG +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# ------------------------------------------------------------------------------ + +"""Test the payloads of the slashing.""" + +import pytest + +from packages.valory.skills.abstract_round_abci.base import ROUND_COUNT_DEFAULT +from packages.valory.skills.slashing_abci.payloads import ( + SlashingTxPayload, + StatusResetPayload, +) + + +@pytest.mark.parametrize( + "sender, tx_hex", + ( + ( + "sender", + "tx_hex", + ), + ), +) +def test_slashing_tx_payload( + sender: str, + tx_hex: str, +) -> None: + """Test `SlashingTxPayload`.""" + + payload = SlashingTxPayload(sender, tx_hex) + + assert payload.id_ + assert payload.round_count == ROUND_COUNT_DEFAULT + assert payload.sender == sender + assert payload.tx_hex == tx_hex + assert payload.data == { + "tx_hex": tx_hex, + "in_progress": True, + "sent": True, + } + + +@pytest.mark.parametrize( + "sender, operators_mapping, slash_timestamps", + ( + ( + "sender", + "mapping", + "timestamps", + ), + ), +) +def test_status_reset_payload( + sender: str, + operators_mapping: str, + slash_timestamps: str, +) -> None: + """Test `StatusResetPayload`""" + + payload = StatusResetPayload( + sender, + operators_mapping, + slash_timestamps, + ) + + assert payload.id_ + assert payload.round_count == ROUND_COUNT_DEFAULT + assert payload.sender == sender + assert payload.operators_mapping == operators_mapping + assert payload.slash_timestamps == slash_timestamps + assert payload.data == { + "operators_mapping": operators_mapping, + "slash_timestamps": slash_timestamps, + "slashing_in_flight": False, + "slash_tx_sent": False, + } diff --git a/packages/valory/skills/slashing_abci/tests/test_rounds.py b/packages/valory/skills/slashing_abci/tests/test_rounds.py new file mode 100644 index 0000000000..1355cf49c4 --- /dev/null +++ b/packages/valory/skills/slashing_abci/tests/test_rounds.py @@ -0,0 +1,142 @@ +# -*- coding: utf-8 -*- +# ------------------------------------------------------------------------------ +# +# Copyright 2023 Valory AG +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# ------------------------------------------------------------------------------ + +"""Tests the slashing background rounds.""" +from copy import deepcopy +from typing import cast +from unittest.mock import MagicMock + +import pytest +from hypothesis import settings + +from packages.valory.skills.abstract_round_abci.base import ( + ABCIAppInternalError, + TransactionNotValidError, +) +from packages.valory.skills.abstract_round_abci.test_tools.rounds import ( + BaseRoundTestClass, +) +from packages.valory.skills.abstract_round_abci.tests.conftest import profile_name +from packages.valory.skills.slashing_abci.payloads import SlashingTxPayload +from packages.valory.skills.slashing_abci.rounds import Event, SlashingCheckRound +from packages.valory.skills.slashing_abci.rounds import ( + SynchronizedData as SlashingSyncedData, +) +from packages.valory.skills.transaction_settlement_abci.rounds import ( + SynchronizedData as TxSettlementSyncedData, +) + + +settings.load_profile(profile_name) + + +class TestSlashingCheckRound(BaseRoundTestClass): + """Tests for `SlashingCheckRound`.""" + + _synchronized_data_class = SlashingSyncedData + + def test_run(self) -> None: + """Run tests.""" + + test_round = SlashingCheckRound( + synchronized_data=self.synchronized_data, + context=MagicMock(), + ) + + first_payload, *payloads = [ + SlashingTxPayload( + sender, + "tx_hex", + ) + for sender in self.participants + ] + + test_round.process_payload(first_payload) + assert test_round.collection == {first_payload.sender: first_payload} + res = test_round.end_block() + assert res is None + + for payload in payloads[:2]: + test_round.process_payload(payload) + res = test_round.end_block() + + expected_state = cast( + SlashingSyncedData, + self.synchronized_data.update( + termination_majority_reached=True, + ), + ) + + assert res is not None + actual_state, event = res + actual_state = cast(SlashingSyncedData, actual_state) + + assert actual_state.slashing_in_flight == expected_state.slashing_in_flight + assert ( + actual_state.slashing_majority_reached + == expected_state.slashing_majority_reached + ) + assert ( + TxSettlementSyncedData(actual_state.db).most_voted_tx_hash + == TxSettlementSyncedData(expected_state.db).most_voted_tx_hash + ) + assert event == Event.SLASH_START + assert not test_round.collection + + def test_bad_payloads(self) -> None: + """Tests the slashing check round when bad payloads are sent.""" + test_round = SlashingCheckRound( + synchronized_data=deepcopy(self.synchronized_data), + context=MagicMock(), + ) + payload_data = "0xdata" + bad_participant = "non_existent" + bad_participant_payload = SlashingTxPayload(bad_participant, payload_data) + first_payload, *_ = [ + SlashingTxPayload(participant, payload_data) + for participant in self.participants + ] + + with pytest.raises( + TransactionNotValidError, + match=f"{bad_participant} not in list of participants", + ): + test_round.check_payload(bad_participant_payload) + + with pytest.raises( + ABCIAppInternalError, + match=f"{bad_participant} not in list of participants", + ): + test_round.process_payload(bad_participant_payload) + + # a valid payload gets sent for the first time and it goes through + test_round.process_payload(first_payload) + + # a duplicate (valid) payload will not go through + with pytest.raises( + TransactionNotValidError, + match=f"sender {first_payload.sender} has already sent value for round", + ): + test_round.check_payload(first_payload) + + with pytest.raises( + ABCIAppInternalError, + match=f"sender {first_payload.sender} has already sent value for round", + ): + test_round.process_payload(first_payload) diff --git a/packages/valory/skills/termination_abci/skill.yaml b/packages/valory/skills/termination_abci/skill.yaml index 55cabc88ab..b5f6df5800 100644 --- a/packages/valory/skills/termination_abci/skill.yaml +++ b/packages/valory/skills/termination_abci/skill.yaml @@ -19,18 +19,18 @@ fingerprint: tests/test_handlers.py: bafybeiefz2ebr5rlyxziwr4bts2r75abpqgji3k47a6hnrj7e7t2yvgmpu tests/test_models.py: bafybeih5wtdjuv4hc25fxneeg7mgjiks55xj353zxfamvtrthkw2ydmbbe tests/test_payloads.py: bafybeibai4dzjjdeyeinyirjndcfzbj2qst6roj6prjvcqwut5m3won3fa - tests/test_rounds.py: bafybeid57gov7piwazxot7qfpjtptkgw24xv67nbdpasqr7pdcwoa7eiea + tests/test_rounds.py: bafybeigpc5xuuhlycjq52gbnw6c33o3yvozpuhzhutrrqdm2wtdgqmkcy4 fingerprint_ignore_patterns: [] connections: [] contracts: -- valory/gnosis_safe:0.1.0:bafybeifvqalsuyetul3ypuolxvxzi5ffxoqdbqpfl3jadqjachsw7qfs74 -- valory/multisend:0.1.0:bafybeigjywkl7hydjsrkogob3xebj2ifhqwmfhhxoeyrndzhhxi5u6amey -- valory/service_registry:0.1.0:bafybeiatzikdgcjteti6xeid4bvofszuavxb4fnczx33lcsvlaui4wpwua +- valory/gnosis_safe:0.1.0:bafybeiegkl6zrbvlbpwmoziw4hfkocjfqdqphkmpgow7ovsmv7bwa3f4pe +- valory/multisend:0.1.0:bafybeig5byt5urg2d2bsecufxe5ql7f4mezg3mekfleeh32nmuusx66p4y +- valory/service_registry:0.1.0:bafybeieeuruq7dp4b6souetv5ce7wlm52pw7vyrxuhqa7kuy5m3rwwxks4 protocols: -- valory/contract_api:1.0.0:bafybeidv6wxpjyb2sdyibnmmum45et4zcla6tl63bnol6ztyoqvpl4spmy +- valory/contract_api:1.0.0:bafybeialhbjvwiwcnqq3ysxcyemobcbie7xza66gaofcvla5njezkvhcka skills: -- valory/abstract_round_abci:0.1.0:bafybeigiolzp3i6b3wwuau3yv2h5udqape3i7of73mlm2d6ud22irlkbme -- valory/transaction_settlement_abci:0.1.0:bafybeifsz2ll7gmy6vmx34t6q5bdv6zzwp5zrehr6di6v3thcpc3sztkta +- valory/abstract_round_abci:0.1.0:bafybeicrzndcdbue34yxwwb4hmmdhgzw4owcdcdag3ifj6thpx5wie3dp4 +- valory/transaction_settlement_abci:0.1.0:bafybeifpnkwgwpzz6uwrvfgurm26allr6shjfbp7bfbrxwy64sw3nf3fsa behaviours: main: args: {} @@ -105,6 +105,7 @@ models: ipfs_domain_name: null keeper_allowed_retries: 3 keeper_timeout: 30.0 + light_slash_unit_amount: 5000000000000000 max_attempts: 10 max_healthcheck: 120 multisend_address: '0xA238CBeb142c10Ef7Ad8442C6D1f9E89e07e7761' @@ -116,10 +117,13 @@ models: retry_attempts: 400 retry_timeout: 3 round_timeout_seconds: 30.0 + serious_slash_unit_amount: 8000000000000000 service_id: termination_abci service_registry_address: '0x48b6af7B12C71f09e2fC8aF4855De4Ff54e775cA' setup: {} share_tm_config_on_startup: false + slash_cooldown_hours: 3 + slash_threshold_amount: 10000000000000000 sleep_time: 1 tendermint_check_sleep_delay: 3 tendermint_com_url: http://localhost:8080 @@ -128,6 +132,7 @@ models: tendermint_url: http://localhost:26657 termination_sleep: 900 tx_timeout: 10.0 + use_slashing: false use_termination: false validate_timeout: 1205 class_name: TerminationParams diff --git a/packages/valory/skills/termination_abci/tests/test_rounds.py b/packages/valory/skills/termination_abci/tests/test_rounds.py index ebb1baa83f..0f439cdfc3 100644 --- a/packages/valory/skills/termination_abci/tests/test_rounds.py +++ b/packages/valory/skills/termination_abci/tests/test_rounds.py @@ -21,6 +21,7 @@ from copy import deepcopy from typing import FrozenSet, cast +from unittest.mock import MagicMock import pytest @@ -79,6 +80,7 @@ def test_run( test_round = BackgroundRound( synchronized_data=deepcopy(self.synchronized_data), + context=MagicMock(), ) payload_data = "0xdata" first_payload, *payloads = [ @@ -115,6 +117,7 @@ def test_bad_payloads(self) -> None: """Tests the background round when bad payloads are sent.""" test_round = BackgroundRound( synchronized_data=deepcopy(self.synchronized_data), + context=MagicMock(), ) payload_data = "0xdata" bad_participant = "non_existent" @@ -165,6 +168,7 @@ def test_run( test_round = TerminationRound( synchronized_data=deepcopy(self.synchronized_data), + context=MagicMock(), ) res = test_round.end_block() # pylint: disable=assignment-from-none assert res is None diff --git a/packages/valory/skills/test_abci/skill.yaml b/packages/valory/skills/test_abci/skill.yaml index a1295e7a39..68d8f5b23e 100644 --- a/packages/valory/skills/test_abci/skill.yaml +++ b/packages/valory/skills/test_abci/skill.yaml @@ -20,14 +20,14 @@ fingerprint: tests/test_handlers.py: bafybeigwsx5yhtxruoqai3cckiupm3wbu3vucxyxnc6us27oa3nnqgs2xe tests/test_models.py: bafybeib7zrd37egmdmoobiahzchur2df2uwyy4hd55dh7l52szzfsb2pwu tests/test_payloads.py: bafybeig54fcpcrxnakyyna6bkxb4dmd7arazsnpvve7tol6rdgkoybluve - tests/test_rounds.py: bafybeifkxbhfcintdvmsgxilnxpfw7kjgst24caznp2moqgfzaah3bztvu + tests/test_rounds.py: bafybeieb3cuobkffsxu7wloerotwo5mowd5x4zsr5b7etvocyf5f32cavq fingerprint_ignore_patterns: [] connections: [] contracts: [] protocols: [] skills: -- valory/abstract_abci:0.1.0:bafybeifuclb6cikagtg2zn7dkjnnv3f7re2tfgzk6c4h3scgyzaaqeg55m -- valory/abstract_round_abci:0.1.0:bafybeigiolzp3i6b3wwuau3yv2h5udqape3i7of73mlm2d6ud22irlkbme +- valory/abstract_abci:0.1.0:bafybeial6drwstqlvuizgtouc4uqgxvutwryfu7yohondemd6bd7cw3jzm +- valory/abstract_round_abci:0.1.0:bafybeicrzndcdbue34yxwwb4hmmdhgzw4owcdcdag3ifj6thpx5wie3dp4 behaviours: main: args: {} @@ -97,6 +97,7 @@ models: version: {} voting_power: '10' keeper_timeout: 30.0 + light_slash_unit_amount: 5000000000000000 max_attempts: 10 max_healthcheck: 120 on_chain_service_id: null @@ -107,6 +108,7 @@ models: retry_attempts: 400 retry_timeout: 3 round_timeout_seconds: 30.0 + serious_slash_unit_amount: 8000000000000000 service_id: test_abci service_registry_address: null setup: @@ -115,6 +117,8 @@ models: safe_contract_address: '0x0000000000000000000000000000000000000000' consensus_threshold: null share_tm_config_on_startup: false + slash_cooldown_hours: 3 + slash_threshold_amount: 10000000000000000 sleep_time: 1 tendermint_check_sleep_delay: 10 tendermint_com_url: http://localhost:8080 @@ -122,6 +126,7 @@ models: tendermint_p2p_url: localhost:26656 tendermint_url: http://localhost:26657 tx_timeout: 10.0 + use_slashing: false use_termination: false class_name: Params randomness_api: diff --git a/packages/valory/skills/test_abci/tests/test_rounds.py b/packages/valory/skills/test_abci/tests/test_rounds.py index 4aa2c63817..a28edee832 100644 --- a/packages/valory/skills/test_abci/tests/test_rounds.py +++ b/packages/valory/skills/test_abci/tests/test_rounds.py @@ -23,6 +23,7 @@ import logging # noqa: F401 from typing import cast +from unittest.mock import MagicMock from packages.valory.skills.abstract_round_abci.base import ( AbciAppDB, @@ -48,6 +49,7 @@ def test_run( test_round = DummyRound( synchronized_data=self.synchronized_data, + context=MagicMock(), ) first_payload, *payloads = [ diff --git a/packages/valory/skills/test_ipfs_abci/skill.yaml b/packages/valory/skills/test_ipfs_abci/skill.yaml index 753ada8ace..6f909cbbe7 100644 --- a/packages/valory/skills/test_ipfs_abci/skill.yaml +++ b/packages/valory/skills/test_ipfs_abci/skill.yaml @@ -21,13 +21,13 @@ fingerprint: tests/test_handlers.py: bafybeicoa6x4tf4pmr5dityxxzp5w2aegn2ubcubxzq7e4minclcwy3cw4 tests/test_models.py: bafybeifyidlrsnut4mrqtenfwo5lmsplp6wm46ej6xide7bvin2j5k7kre tests/test_payloads.py: bafybeihdizr6r5xnd5hudj7ho7ye3dkcppjt753ulaofyazqpokxnf6cga - tests/test_rounds.py: bafybeidmmr4vevplodp6zz55cqarlyv5gufqnofmqpepwwhvpeitexhvl4 + tests/test_rounds.py: bafybeiauoo6cg6srmyxcpdmsic4nvoq4ddniq4zx2t7wzzvbiir6bpgkya fingerprint_ignore_patterns: [] connections: [] contracts: [] protocols: [] skills: -- valory/abstract_round_abci:0.1.0:bafybeigiolzp3i6b3wwuau3yv2h5udqape3i7of73mlm2d6ud22irlkbme +- valory/abstract_round_abci:0.1.0:bafybeicrzndcdbue34yxwwb4hmmdhgzw4owcdcdag3ifj6thpx5wie3dp4 behaviours: main: args: {} @@ -101,6 +101,7 @@ models: init_fallback_gas: 0 keeper_allowed_retries: 3 keeper_timeout: 30.0 + light_slash_unit_amount: 5000000000000000 max_attempts: 10 max_healthcheck: 120 multisend_address: '0xA238CBeb142c10Ef7Ad8442C6D1f9E89e07e7761' @@ -112,6 +113,7 @@ models: retry_attempts: 400 retry_timeout: 3 round_timeout_seconds: 30.0 + serious_slash_unit_amount: 8000000000000000 service_id: test_ipfs_abci service_registry_address: null setup: @@ -120,6 +122,8 @@ models: safe_contract_address: '0x0000000000000000000000000000000000000000' consensus_threshold: null share_tm_config_on_startup: false + slash_cooldown_hours: 3 + slash_threshold_amount: 10000000000000000 sleep_time: 1 tendermint_check_sleep_delay: 3 tendermint_com_url: http://localhost:8080 @@ -128,6 +132,7 @@ models: tendermint_url: http://localhost:26657 termination_sleep: 900 tx_timeout: 10.0 + use_slashing: false use_termination: false validate_timeout: 1205 class_name: Params diff --git a/packages/valory/skills/test_ipfs_abci/tests/test_rounds.py b/packages/valory/skills/test_ipfs_abci/tests/test_rounds.py index 0ae8322d76..d50823d253 100644 --- a/packages/valory/skills/test_ipfs_abci/tests/test_rounds.py +++ b/packages/valory/skills/test_ipfs_abci/tests/test_rounds.py @@ -27,5 +27,6 @@ def test_end_block() -> None: """Test IpfsRound.end_block()""" dummy_round = IpfsRound( synchronized_data=MagicMock(max_participants=4), + context=MagicMock(), ) dummy_round.end_block() diff --git a/packages/valory/skills/transaction_settlement_abci/behaviours.py b/packages/valory/skills/transaction_settlement_abci/behaviours.py index f871b32086..dfc02bdbd5 100644 --- a/packages/valory/skills/transaction_settlement_abci/behaviours.py +++ b/packages/valory/skills/transaction_settlement_abci/behaviours.py @@ -89,7 +89,6 @@ TxDataType = Dict[str, Union[VerificationStatus, Deque[str], int, Set[str], str]] - drand_check = VerifyDrand() REVERT_CODE_RE = r"\s(GS\d{3})[^\d]" @@ -166,7 +165,12 @@ def get_gas_price_params(self, tx_body: dict) -> List[str]: return [] def _get_tx_data( - self, message: ContractApiMessage, use_flashbots: bool + self, + message: ContractApiMessage, + use_flashbots: bool, + manual_gas_limit: int = 0, + raise_on_failed_simulation: bool = False, + chain_id: Optional[str] = None, ) -> Generator[None, None, TxDataType]: """Get the transaction data from a `ContractApiMessage`.""" tx_data: TxDataType = { @@ -196,9 +200,15 @@ def _get_tx_data( ) return tx_data + if manual_gas_limit > 0: + message.raw_transaction.body["gas"] = manual_gas_limit + # Send transaction tx_digest, rpc_status = yield from self.send_raw_transaction( - message.raw_transaction, use_flashbots + message.raw_transaction, + use_flashbots, + raise_on_failed_simulation=raise_on_failed_simulation, + chain_id=chain_id, ) # Handle transaction results @@ -274,7 +284,7 @@ def _verify_tx(self, tx_hash: str) -> Generator[None, None, ContractApiMessage]: tx_params = skill_input_hex_to_payload( self.synchronized_data.most_voted_tx_hash ) - + chain_id = self.synchronized_data.get_chain_id(self.params.default_chain_id) contract_api_msg = yield from self.get_contract_api_response( performative=ContractApiMessage.Performative.GET_STATE, # type: ignore contract_address=self.synchronized_data.safe_contract_address, @@ -291,8 +301,8 @@ def _verify_tx(self, tx_hash: str) -> Generator[None, None, ContractApiMessage]: for key, payload in self.synchronized_data.participant_to_signature.items() }, operation=tx_params["operation"], + chain_id=chain_id, ) - return contract_api_msg @staticmethod @@ -320,6 +330,18 @@ def _parse_revert_reason(message: ContractApiMessage) -> str: return f"Received a {revert_code} revert error: {revert_explanation}." + def _get_safe_nonce(self) -> Generator[None, None, ContractApiMessage]: + """Get the safe nonce.""" + chain_id = self.synchronized_data.get_chain_id(self.params.default_chain_id) + contract_api_msg = yield from self.get_contract_api_response( + performative=ContractApiMessage.Performative.GET_STATE, # type: ignore + contract_address=self.synchronized_data.safe_contract_address, + contract_id=str(GnosisSafeContract.contract_id), + contract_callable="get_safe_nonce", + chain_id=chain_id, + ) + return contract_api_msg + class RandomnessTransactionSubmissionBehaviour(RandomnessBehaviour): """Retrieve randomness.""" @@ -381,9 +403,7 @@ def async_act(self) -> Generator: keepers = self.synchronized_data.keepers keeper_retries = 1 - if ( - self.synchronized_data.keepers_threshold_exceeded - ): # TODO: I think this should be second prio + if self.synchronized_data.keepers_threshold_exceeded: keepers.rotate(-1) self.context.logger.info(f"Rotated keepers to: {keepers}.") elif ( @@ -527,7 +547,7 @@ def async_act(self) -> Generator: self.set_done() - def _check_tx_history( + def _check_tx_history( # pylint: disable=too-many-return-statements self, ) -> Generator[None, None, Tuple[VerificationStatus, Optional[str]]]: """Check the transaction history.""" @@ -538,9 +558,32 @@ def _check_tx_history( ) return VerificationStatus.ERROR, None + contract_api_msg = yield from self._get_safe_nonce() + if ( + contract_api_msg.performative != ContractApiMessage.Performative.STATE + ): # pragma: nocover + self.context.logger.error( + f"get_safe_nonce unsuccessful! Received: {contract_api_msg}" + ) + return VerificationStatus.ERROR, None + + safe_nonce = cast(int, contract_api_msg.state.body["safe_nonce"]) + if safe_nonce == self.params.mutable_params.nonce: + # if we have reached this state it means that the transaction didn't go through in the expected time + # as such we assume it is not verified + self.context.logger.info( + f"Safe nonce is the same as the nonce used in the transaction: {safe_nonce}. " + f"No transaction has gone through yet." + ) + return VerificationStatus.NOT_VERIFIED, None + self.context.logger.info( - f"Starting check for the transaction history: {self.history}." + f"A transaction with nonce {safe_nonce} has already been sent. " ) + self.context.logger.info( + f"Starting check for the transaction history: {self.history}. " + ) + was_nonce_reused = False for tx_hash in self.history[::-1]: self.context.logger.info(f"Checking hash {tx_hash}...") contract_api_msg = yield from self._verify_tx(tx_hash) @@ -583,6 +626,7 @@ def _check_tx_history( f"The safe's nonce has been reused for {tx_hash}. " f"{self.check_expected_to_be_verified} is expected to be verified!" ) + was_nonce_reused = True # this loop might take a long time # we do not want to starve the rest of the behaviour # we yield which freezes this loop here until the @@ -596,16 +640,25 @@ def _check_tx_history( return VerificationStatus.INVALID_PAYLOAD, tx_hash + if was_nonce_reused: + self.context.logger.info( + f"Safe nonce {safe_nonce} was used, but no valid transaction was found. " + f"We cannot resend the transaction with the same nonce." + ) + return VerificationStatus.BAD_SAFE_NONCE, None + return VerificationStatus.NOT_VERIFIED, None def _get_revert_reason(self, tx: TxData) -> Generator[None, None, Optional[str]]: """Get the revert reason of the given transaction.""" + chain_id = self.synchronized_data.get_chain_id(self.params.default_chain_id) contract_api_msg = yield from self.get_contract_api_response( performative=ContractApiMessage.Performative.GET_STATE, # type: ignore contract_address=self.synchronized_data.safe_contract_address, contract_id=str(GnosisSafeContract.contract_id), contract_callable="revert_reason", tx=tx, + chain_id=chain_id, ) if ( @@ -666,8 +719,13 @@ def async_act(self) -> Generator: with self.context.benchmark_tool.measure(self.behaviour_id).local(): current_message = next(self._messages_iterator, None) if current_message is not None: + chain_id = self.synchronized_data.get_chain_id( + self.params.default_chain_id + ) tx_data = yield from self._get_tx_data( - current_message, self.use_flashbots + current_message, + self.use_flashbots, + chain_id=chain_id, ) self.context.logger.info( f"Found a late arriving message {current_message}. Result data: {tx_data}" @@ -836,7 +894,7 @@ def _send_safe_transaction( tx_params = skill_input_hex_to_payload( self.synchronized_data.most_voted_tx_hash ) - + chain_id = self.synchronized_data.get_chain_id(self.params.default_chain_id) contract_api_msg = yield from self.get_contract_api_response( performative=ContractApiMessage.Performative.GET_RAW_TRANSACTION, # type: ignore contract_address=self.synchronized_data.safe_contract_address, @@ -856,10 +914,18 @@ def _send_safe_transaction( old_price=self.params.mutable_params.gas_price, operation=tx_params["operation"], fallback_gas=self.params.mutable_params.fallback_gas, + gas_price=self.params.gas_params.gas_price, + max_fee_per_gas=self.params.gas_params.max_fee_per_gas, + max_priority_fee_per_gas=self.params.gas_params.max_priority_fee_per_gas, + chain_id=chain_id, ) tx_data = yield from self._get_tx_data( - contract_api_msg, tx_params["use_flashbots"] + contract_api_msg, + tx_params["use_flashbots"], + tx_params["gas_limit"], + tx_params["raise_on_failed_simulation"], + chain_id, ) return tx_data diff --git a/packages/valory/skills/transaction_settlement_abci/fsm_specification.yaml b/packages/valory/skills/transaction_settlement_abci/fsm_specification.yaml index 6554107dc1..70b6e1f22c 100644 --- a/packages/valory/skills/transaction_settlement_abci/fsm_specification.yaml +++ b/packages/valory/skills/transaction_settlement_abci/fsm_specification.yaml @@ -31,8 +31,8 @@ states: - RandomnessTransactionSubmissionRound - ResetRound - SelectKeeperTransactionSubmissionARound -- SelectKeeperTransactionSubmissionBRound - SelectKeeperTransactionSubmissionBAfterTimeoutRound +- SelectKeeperTransactionSubmissionBRound - SynchronizeLateMessagesRound - ValidateTransactionRound transition_func: @@ -67,16 +67,16 @@ transition_func: (SelectKeeperTransactionSubmissionARound, INCORRECT_SERIALIZATION): FailedRound (SelectKeeperTransactionSubmissionARound, NO_MAJORITY): ResetRound (SelectKeeperTransactionSubmissionARound, ROUND_TIMEOUT): SelectKeeperTransactionSubmissionARound - (SelectKeeperTransactionSubmissionBRound, DONE): FinalizationRound - (SelectKeeperTransactionSubmissionBRound, INCORRECT_SERIALIZATION): FailedRound - (SelectKeeperTransactionSubmissionBRound, NO_MAJORITY): ResetRound - (SelectKeeperTransactionSubmissionBRound, ROUND_TIMEOUT): SelectKeeperTransactionSubmissionBRound (SelectKeeperTransactionSubmissionBAfterTimeoutRound, CHECK_HISTORY): CheckTransactionHistoryRound (SelectKeeperTransactionSubmissionBAfterTimeoutRound, CHECK_LATE_ARRIVING_MESSAGE): SynchronizeLateMessagesRound (SelectKeeperTransactionSubmissionBAfterTimeoutRound, DONE): FinalizationRound (SelectKeeperTransactionSubmissionBAfterTimeoutRound, INCORRECT_SERIALIZATION): FailedRound (SelectKeeperTransactionSubmissionBAfterTimeoutRound, NO_MAJORITY): ResetRound (SelectKeeperTransactionSubmissionBAfterTimeoutRound, ROUND_TIMEOUT): SelectKeeperTransactionSubmissionBAfterTimeoutRound + (SelectKeeperTransactionSubmissionBRound, DONE): FinalizationRound + (SelectKeeperTransactionSubmissionBRound, INCORRECT_SERIALIZATION): FailedRound + (SelectKeeperTransactionSubmissionBRound, NO_MAJORITY): ResetRound + (SelectKeeperTransactionSubmissionBRound, ROUND_TIMEOUT): SelectKeeperTransactionSubmissionBRound (SynchronizeLateMessagesRound, DONE): CheckLateTxHashesRound (SynchronizeLateMessagesRound, NONE): SelectKeeperTransactionSubmissionBRound (SynchronizeLateMessagesRound, ROUND_TIMEOUT): SynchronizeLateMessagesRound @@ -85,4 +85,4 @@ transition_func: (ValidateTransactionRound, NEGATIVE): CheckTransactionHistoryRound (ValidateTransactionRound, NONE): SelectKeeperTransactionSubmissionBRound (ValidateTransactionRound, NO_MAJORITY): ValidateTransactionRound - (ValidateTransactionRound, VALIDATE_TIMEOUT): SelectKeeperTransactionSubmissionBRound + (ValidateTransactionRound, VALIDATE_TIMEOUT): CheckTransactionHistoryRound diff --git a/packages/valory/skills/transaction_settlement_abci/models.py b/packages/valory/skills/transaction_settlement_abci/models.py index 30fa6ca33a..e65bb69324 100644 --- a/packages/valory/skills/transaction_settlement_abci/models.py +++ b/packages/valory/skills/transaction_settlement_abci/models.py @@ -59,6 +59,15 @@ class MutableParams(TypeCheckMixin): late_messages: List[ContractApiMessage] = field(default_factory=list) +@dataclass +class GasParams(BaseParams): + """Gas parameters.""" + + gas_price: Optional[int] = None + max_fee_per_gas: Optional[int] = None + max_priority_fee_per_gas: Optional[int] = None + + class TransactionParams(BaseParams): # pylint: disable=too-many-instance-attributes """Transaction settlement agent-specific parameters.""" @@ -93,8 +102,22 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: self.history_check_timeout: int = self._ensure( "history_check_timeout", kwargs, int ) + self.gas_params = self._get_gas_params(kwargs) super().__init__(*args, **kwargs) + @staticmethod + def _get_gas_params(kwargs: Dict[str, Any]) -> GasParams: + """Get the gas parameters.""" + gas_params = kwargs.pop("gas_params", {}) + gas_price = gas_params.get("gas_price", None) + max_fee_per_gas = gas_params.get("max_fee_per_gas", None) + max_priority_fee_per_gas = gas_params.get("max_priority_fee_per_gas", None) + return GasParams( + gas_price=gas_price, + max_fee_per_gas=max_fee_per_gas, + max_priority_fee_per_gas=max_priority_fee_per_gas, + ) + RandomnessApi = ApiSpecs Requests = BaseRequests diff --git a/packages/valory/skills/transaction_settlement_abci/payload_tools.py b/packages/valory/skills/transaction_settlement_abci/payload_tools.py index 682b425b23..44a86883f3 100644 --- a/packages/valory/skills/transaction_settlement_abci/payload_tools.py +++ b/packages/valory/skills/transaction_settlement_abci/payload_tools.py @@ -38,6 +38,7 @@ class VerificationStatus(Enum): PENDING = 4 ERROR = 5 INSUFFICIENT_FUNDS = 6 + BAD_SAFE_NONCE = 7 class PayloadDeserializationError(Exception): @@ -100,6 +101,8 @@ def hash_payload_to_hex( # pylint: disable=too-many-arguments, too-many-locals gas_token: str = NULL_ADDRESS, refund_receiver: str = NULL_ADDRESS, use_flashbots: bool = False, + gas_limit: int = 0, + raise_on_failed_simulation: bool = False, ) -> str: """Serialise to a hex string.""" if len(safe_tx_hash) != 64: # should be exactly 32 bytes! @@ -115,6 +118,7 @@ def hash_payload_to_hex( # pylint: disable=too-many-arguments, too-many-locals or safe_tx_gas > MAX_UINT256 or base_gas > MAX_UINT256 or safe_gas_price > MAX_UINT256 + or gas_limit > MAX_UINT256 ): raise ValueError( "Value is bigger than the max 256 bit value" @@ -134,6 +138,8 @@ def hash_payload_to_hex( # pylint: disable=too-many-arguments, too-many-locals base_gas_ = base_gas.to_bytes(32, "big").hex() safe_gas_price_ = safe_gas_price.to_bytes(32, "big").hex() use_flashbots_ = use_flashbots.to_bytes(32, "big").hex() + gas_limit_ = gas_limit.to_bytes(32, "big").hex() + raise_on_failed_simulation_ = raise_on_failed_simulation.to_bytes(32, "big").hex() concatenated = ( safe_tx_hash @@ -146,6 +152,8 @@ def hash_payload_to_hex( # pylint: disable=too-many-arguments, too-many-locals + gas_token + refund_receiver + use_flashbots_ + + gas_limit_ + + raise_on_failed_simulation_ + data.hex() ) return concatenated @@ -166,6 +174,10 @@ def skill_input_hex_to_payload(payload: str) -> dict: gas_token=payload[364:406], refund_receiver=payload[406:448], use_flashbots=bool.from_bytes(bytes.fromhex(payload[448:512]), "big"), - data=bytes.fromhex(payload[512:]), + gas_limit=int.from_bytes(bytes.fromhex(payload[512:576]), "big"), + raise_on_failed_simulation=bool.from_bytes( + bytes.fromhex(payload[576:640]), "big" + ), + data=bytes.fromhex(payload[640:]), ) return tx_params diff --git a/packages/valory/skills/transaction_settlement_abci/rounds.py b/packages/valory/skills/transaction_settlement_abci/rounds.py index 03d2ef632f..d6231ee3db 100644 --- a/packages/valory/skills/transaction_settlement_abci/rounds.py +++ b/packages/valory/skills/transaction_settlement_abci/rounds.py @@ -245,6 +245,10 @@ def participant_to_late_messages( deserialized = CollectionRound.deserialize_collection(serialized) return cast(Mapping[str, SynchronizeLateMessagesPayload], deserialized) + def get_chain_id(self, default_chain_id: str) -> str: + """Get the chain id.""" + return cast(str, self.db.get("chain_id", default_chain_id)) + class FailedRound(DegenerateRound, ABC): """A round that represents that the period failed""" @@ -458,7 +462,9 @@ class CheckTransactionHistoryRound(CollectSameUntilThresholdRound): collection_key = get_name(SynchronizedData.participant_to_check) selection_key = get_name(SynchronizedData.most_voted_check_result) - def end_block(self) -> Optional[Tuple[BaseSynchronizedData, Enum]]: + def end_block( # pylint: disable=too-many-return-statements + self, + ) -> Optional[Tuple[BaseSynchronizedData, Enum]]: """Process the end of the block.""" if self.threshold_reached: return_status, return_tx_hash = tx_hist_hex_to_payload( @@ -495,6 +501,9 @@ def end_block(self) -> Optional[Tuple[BaseSynchronizedData, Enum]]: return synchronized_data, Event.CHECK_LATE_ARRIVING_MESSAGE if return_status == VerificationStatus.NOT_VERIFIED: return synchronized_data, Event.NEGATIVE + if return_status == VerificationStatus.BAD_SAFE_NONCE: + # in case a bad nonce was used, we need to recreate the tx from scratch + return synchronized_data, Event.NONE return synchronized_data, Event.NONE @@ -666,7 +675,7 @@ class TransactionSubmissionAbciApp(AbciApp[Event]): - done: 11. - negative: 5. - none: 6. - - validate timeout: 6. + - validate timeout: 5. - no majority: 4. 5. CheckTransactionHistoryRound - done: 11. @@ -747,7 +756,9 @@ class TransactionSubmissionAbciApp(AbciApp[Event]): Event.DONE: FinishedTransactionSubmissionRound, Event.NEGATIVE: CheckTransactionHistoryRound, Event.NONE: SelectKeeperTransactionSubmissionBRound, - Event.VALIDATE_TIMEOUT: SelectKeeperTransactionSubmissionBRound, + # even in case of timeout we might've sent the transaction + # so we need to check the history + Event.VALIDATE_TIMEOUT: CheckTransactionHistoryRound, Event.NO_MAJORITY: ValidateTransactionRound, }, CheckTransactionHistoryRound: { diff --git a/packages/valory/skills/transaction_settlement_abci/skill.yaml b/packages/valory/skills/transaction_settlement_abci/skill.yaml index a7fe5fc132..00e7e0ec91 100644 --- a/packages/valory/skills/transaction_settlement_abci/skill.yaml +++ b/packages/valory/skills/transaction_settlement_abci/skill.yaml @@ -8,37 +8,37 @@ aea_version: '>=1.0.0, <2.0.0' fingerprint: README.md: bafybeihvqvbj2tiiyimz3e27gqhb7ku5rut7hycfahi4qle732kvj5fs7q __init__.py: bafybeicyrp6x2efg43gfdekxuofrlidc3w6aubzmyioqwnryropp6u7sby - behaviours.py: bafybeiac22flb67zjdjpnhbm33u3zqpszl6kr76p6k3mic2jyqvr33wjgq + behaviours.py: bafybeibsbeclxwxgbcqd7gorsr2sf2mgsrkcxb5kioglzfzvkcstb7biwe dialogues.py: bafybeigabhaykiyzbluu4mk6bbrmqhzld2kyp32pg24bvjmzrrb74einwm - fsm_specification.yaml: bafybeih5w3uwshxzpslvv6zccw6a5lq6fiypgr6alhabytcketwnxrzfem + fsm_specification.yaml: bafybeigdj64py4zjihcxdkvtrydbxyeh4slr2kkghltz3upnupdgad4et4 handlers.py: bafybeie42qa3csgy6oompuqs2qnkat5mnslepbbwmgoxv6ljme4jofa5pe - models.py: bafybeieziji7agfrod5hoj62j34psjawmbma2r6cl57bqy7yxyb7m45ygy - payload_tools.py: bafybeig5cjypnpd3guhomlwldcjull3jntxo46hrbehqhxaxnqmdmsqdoy + models.py: bafybeiguxishqvtvlyznok3xjnzm4t6vfflamcvz5vtecq5esbldsxuc5e + payload_tools.py: bafybeiatlbw3vyo5ppjhxf4psdvkwubmrjolsprf44lis5ozfkjo7o3cba payloads.py: bafybeiclhjnsgylqzfnu2azlqxor3vyldaoof757dnfwz5xbwejk2ro2cm - rounds.py: bafybeic5t3epyzfpumzv3ggvq7aenvd7of34cyqhyzs6foycbq2uv5a64i + rounds.py: bafybeieo5l6gh276hhtztphloyknb5ew66hvqhzzjiv26isaz7ptvtqjgu test_tools/__init__.py: bafybeibj2blgxzvcgdi5gzcnlzs2nt7bpdifzvjjlxlrkeutjy2qrqbwau test_tools/integration.py: bafybeictb7ym4xsbo3ti5y2a2fpg344graa4d7352oozsea5rbab3kq4ae tests/__init__.py: bafybeifukcwmf2ewkjqdu7j6xzmaovgrul7jnea5lrl4o3ianoofje6vfa - tests/test_behaviours.py: bafybeici37gttvhpcufar457oky4opaql2nwqj6lwlsnbg52uapg2fcobm + tests/test_behaviours.py: bafybeia2vob5legv3tdrdj4gjgmnz6enhaterbetkc6ntdemnwgg5or4gq tests/test_dialogues.py: bafybeictrjf6jzsj4y6u2ftdrb2nyriiipia5b7wc4fsli3lwbjpd3mbam tests/test_handlers.py: bafybeievntkwacpfaom3qabvrlworjqyd4sgfjknjlhys7f5tuq7725xli - tests/test_models.py: bafybeifysgk6xywarymqbfwnpkjlzrjxtxkgm26k3mfiyerqvovwyyhqsa - tests/test_payload_tools.py: bafybeihyw5ea22gw3p2iz3ipce3rjkglwptaa2p2cvtqr4sfus4pi5blhu + tests/test_models.py: bafybeihvrv7vtaei64nv7okkfz2gg2g4ey4nei27ayc74h5bdlqpbk4xde + tests/test_payload_tools.py: bafybeihmgkcrlqhz4ncak276lnccmilig6gx3crmn33n46jcco6g5pzrje tests/test_payloads.py: bafybeidvjqvjvnuw5vt4zgnqwzopvprznmefosqy3wcxukvobaiishygze - tests/test_rounds.py: bafybeicx644a742mnebxkxufuhmbcc4zasyol6daycnmfdpbawfvbc6rfu + tests/test_rounds.py: bafybeic3kzqy3pe6d4skntnfc5443y6dshcustiuv2d6cw4z56gw2ewehy tests/test_tools/__init__.py: bafybeiaq2ftmklvu5vqq6vdfa7mrlmrnusluki35jm5n2yzf57ox5dif74 tests/test_tools/test_integration.py: bafybeigv6fxogm3aq3extahr75owdqnzepouv3rtxl3m4gai2urtz6u4ea fingerprint_ignore_patterns: [] connections: [] contracts: -- valory/gnosis_safe:0.1.0:bafybeifvqalsuyetul3ypuolxvxzi5ffxoqdbqpfl3jadqjachsw7qfs74 +- valory/gnosis_safe:0.1.0:bafybeiegkl6zrbvlbpwmoziw4hfkocjfqdqphkmpgow7ovsmv7bwa3f4pe protocols: -- open_aea/signing:1.0.0:bafybeibqlfmikg5hk4phzak6gqzhpkt6akckx7xppbp53mvwt6r73h7tk4 -- valory/abci:0.1.0:bafybeig3dj5jhsowlvg3t73kgobf6xn4nka7rkttakdb2gwsg5bp7rt7q4 -- valory/contract_api:1.0.0:bafybeidv6wxpjyb2sdyibnmmum45et4zcla6tl63bnol6ztyoqvpl4spmy -- valory/ledger_api:1.0.0:bafybeibo4bdtcrxi2suyzldwoetjar6pqfzm6vt5xal22ravkkcvdmtksi +- open_aea/signing:1.0.0:bafybeie7xyems76v5b4wc2lmaidcujizpxfzjnnwdeokmhje53g7ym25ii +- valory/abci:0.1.0:bafybeihmzlmmb4pdo3zkhg6ehuyaa4lhw7bfpclln2o2z7v3o6fcep26iu +- valory/contract_api:1.0.0:bafybeialhbjvwiwcnqq3ysxcyemobcbie7xza66gaofcvla5njezkvhcka +- valory/ledger_api:1.0.0:bafybeige5agrztgzfevyglf7mb4o7pzfttmq4f6zi765y4g2zvftbyowru skills: -- valory/abstract_round_abci:0.1.0:bafybeigiolzp3i6b3wwuau3yv2h5udqape3i7of73mlm2d6ud22irlkbme +- valory/abstract_round_abci:0.1.0:bafybeicrzndcdbue34yxwwb4hmmdhgzw4owcdcdag3ifj6thpx5wie3dp4 behaviours: main: args: {} @@ -112,6 +112,7 @@ models: init_fallback_gas: 0 keeper_allowed_retries: 3 keeper_timeout: 30.0 + light_slash_unit_amount: 5000000000000000 max_attempts: 10 max_healthcheck: 120 on_chain_service_id: null @@ -122,10 +123,13 @@ models: retry_attempts: 400 retry_timeout: 3 round_timeout_seconds: 30.0 + serious_slash_unit_amount: 8000000000000000 service_id: registration service_registry_address: null setup: {} share_tm_config_on_startup: false + slash_cooldown_hours: 3 + slash_threshold_amount: 10000000000000000 sleep_time: 1 tendermint_check_sleep_delay: 3 tendermint_com_url: http://localhost:8080 @@ -133,8 +137,10 @@ models: tendermint_p2p_url: localhost:26656 tendermint_url: http://localhost:26657 tx_timeout: 10.0 + use_slashing: false use_termination: false validate_timeout: 1205 + default_chain_id: ethereum class_name: TransactionParams randomness_api: args: @@ -161,7 +167,7 @@ models: class_name: TendermintDialogues dependencies: open-aea-test-autonomy: - version: ==0.10.2 + version: ==0.13.9.post1 web3: - version: ==5.25.0 + version: <7,>=6.0.0 is_abstract: true diff --git a/packages/valory/skills/transaction_settlement_abci/tests/test_behaviours.py b/packages/valory/skills/transaction_settlement_abci/tests/test_behaviours.py index 6614f96b06..fbc6d9f930 100644 --- a/packages/valory/skills/transaction_settlement_abci/tests/test_behaviours.py +++ b/packages/valory/skills/transaction_settlement_abci/tests/test_behaviours.py @@ -341,7 +341,7 @@ def test__get_tx_data( # patch the `send_raw_transaction` method def dummy_send_raw_transaction( - *_: Any, + *_: Any, **kwargs: Any ) -> Generator[None, None, Tuple[Optional[str], RPCResponseStatus]]: """Dummy `send_raw_transaction` method.""" yield @@ -1141,6 +1141,22 @@ def test_check_tx_history_behaviour( self.behaviour.act_wrapper() if hashes_history: + self.mock_contract_api_request( + request_kwargs=dict( + performative=ContractApiMessage.Performative.GET_STATE + ), + contract_id=str(GNOSIS_SAFE_CONTRACT_ID), + response_kwargs=dict( + performative=ContractApiMessage.Performative.STATE, + callable="get_safe_nonce", + state=TrState( + ledger_id="ethereum", + body={ + "safe_nonce": 0, + }, + ), + ), + ) self.mock_contract_api_request( request_kwargs=dict( performative=ContractApiMessage.Performative.GET_STATE @@ -1186,6 +1202,50 @@ def test_check_tx_history_behaviour( ).auto_behaviour_id() ) + @pytest.mark.parametrize( + "verified, status, hashes_history, revert_reason", + ((False, 0, "0x" + "t" * 64, "test"),), + ) + def test_check_tx_history_behaviour_negative( + self, + verified: bool, + status: int, + hashes_history: str, + revert_reason: str, + ) -> None: + """Test CheckTransactionHistoryBehaviour.""" + self._fast_forward(hashes_history) + self.behaviour.act_wrapper() + self.behaviour.context.params.mutable_params.nonce = 1 + if hashes_history: + self.mock_contract_api_request( + request_kwargs=dict( + performative=ContractApiMessage.Performative.GET_STATE + ), + contract_id=str(GNOSIS_SAFE_CONTRACT_ID), + response_kwargs=dict( + performative=ContractApiMessage.Performative.STATE, + callable="get_safe_nonce", + state=TrState( + ledger_id="ethereum", + body={ + "safe_nonce": 1, + }, + ), + ), + ) + self.behaviour.act_wrapper() + self.mock_a2a_transaction() + self._test_done_flag_set() + self.end_round(TransactionSettlementEvent.DONE) + behaviour = cast(BaseBehaviour, self.behaviour.current_behaviour) + assert ( + behaviour.behaviour_id + == make_degenerate_behaviour( + FinishedTransactionSubmissionRound + ).auto_behaviour_id() + ) + class TestCheckLateTxHashesBehaviour(TransactionSettlementFSMBehaviourBaseCase): """Test CheckLateTxHashesBehaviour.""" @@ -1282,6 +1342,7 @@ def test_async_act(self, late_messages: List[MagicMock]) -> None: def _dummy_get_tx_data( _current_message: ContractApiMessage, _use_flashbots: bool, + chain_id: Optional[str] = None, ) -> Generator[None, None, TxDataType]: yield return { diff --git a/packages/valory/skills/transaction_settlement_abci/tests/test_models.py b/packages/valory/skills/transaction_settlement_abci/tests/test_models.py index 24d1e2e2b2..746f0a312f 100644 --- a/packages/valory/skills/transaction_settlement_abci/tests/test_models.py +++ b/packages/valory/skills/transaction_settlement_abci/tests/test_models.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- # ------------------------------------------------------------------------------ # -# Copyright 2022 Valory AG +# Copyright 2022-2023 Valory AG # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -19,7 +19,7 @@ # pylint: disable=unused-import """Test the models.py module of the skill.""" -from typing import Dict +from typing import Any, Dict from unittest.mock import MagicMock import pytest @@ -64,3 +64,32 @@ def test_ensure_validate_timeout( # pylint: disable=no-self-use match=f"`validate_timeout` must be greater than or equal to {_MINIMUM_VALIDATE_TIMEOUT}", ): TransactionParams(mock_args, **mock_kwargs) + + @pytest.mark.parametrize( + "gas_params", + [ + {}, + {"gas_price": 1}, + {"max_fee_per_gas": 1}, + {"max_priority_fee_per_gas": 1}, + { + "gas_price": 1, + "max_fee_per_gas": 1, + "max_priority_fee_per_gas": 1, + }, + ], + ) + def test_gas_params(self, gas_params: Dict[str, Any]) -> None: + """Test that gas params are being handled properly.""" + mock_args, mock_kwargs = ( + MagicMock(), + { + **self.default_config, + "gas_params": gas_params, + "skill_context": DummyContext(), + }, + ) + params = TransactionParams(mock_args, **mock_kwargs) + # verify that the gas params are being set properly + for key, value in gas_params.items(): + assert getattr(params.gas_params, key) == value diff --git a/packages/valory/skills/transaction_settlement_abci/tests/test_payload_tools.py b/packages/valory/skills/transaction_settlement_abci/tests/test_payload_tools.py index 88c735f032..91a90cf81b 100644 --- a/packages/valory/skills/transaction_settlement_abci/tests/test_payload_tools.py +++ b/packages/valory/skills/transaction_settlement_abci/tests/test_payload_tools.py @@ -67,7 +67,7 @@ def test_invalid_tx_hash_during_serialization() -> None: @staticmethod @pytest.mark.parametrize( "payload", - ("0000000000000000000000000000000000000000000000000000000000000007", ""), + ("0000000000000000000000000000000000000000000000000000000000000008", ""), ) def test_invalid_payloads_during_deserialization(payload: str) -> None: """Test decoding payload is invalid.""" @@ -92,7 +92,9 @@ def test_payload_to_hex_and_back(use_flashbots: bool) -> None: safe_gas_price=0, gas_token=NULL_ADDRESS, use_flashbots=use_flashbots, + gas_limit=0, refund_receiver=NULL_ADDRESS, + raise_on_failed_simulation=False, ) intermediate = hash_payload_to_hex(**tx_params) # type: ignore diff --git a/packages/valory/skills/transaction_settlement_abci/tests/test_rounds.py b/packages/valory/skills/transaction_settlement_abci/tests/test_rounds.py index addf2cdfde..ecdb1af88c 100644 --- a/packages/valory/skills/transaction_settlement_abci/tests/test_rounds.py +++ b/packages/valory/skills/transaction_settlement_abci/tests/test_rounds.py @@ -37,6 +37,7 @@ cast, ) from unittest import mock +from unittest.mock import MagicMock import pytest @@ -262,6 +263,7 @@ def test_positive_votes( test_round = self.test_class( synchronized_data=self.synchronized_data, + context=MagicMock(), ) self._complete_run( @@ -287,6 +289,7 @@ def test_negative_votes( test_round = self.test_class( synchronized_data=self.synchronized_data, + context=MagicMock(), ) self._complete_run( @@ -310,6 +313,7 @@ def test_none_votes( test_round = self.test_class( synchronized_data=self.synchronized_data, + context=MagicMock(), ) self._complete_run( @@ -353,6 +357,7 @@ def test_run( synchronized_data=self.synchronized_data.update( keepers=keepers, ), + context=MagicMock(), ) self._complete_run( @@ -618,6 +623,7 @@ def test_finalization_round( test_round = self._round_class( synchronized_data=self.synchronized_data, + context=MagicMock(), ) self._complete_run( @@ -667,6 +673,7 @@ def test_finalization_round_no_tx_data(self) -> None: test_round = self._round_class( synchronized_data=self.synchronized_data, + context=MagicMock(), ) self._complete_run( @@ -702,6 +709,7 @@ def test_run( test_round = CollectSignatureRound( synchronized_data=self.synchronized_data, + context=MagicMock(), ) self._complete_run( @@ -750,6 +758,12 @@ class TestCheckTransactionHistoryRound(BaseCollectSameUntilThresholdRoundTest): {}, TransactionSettlementEvent.NONE, ), + ( + "0000000000000000000000000000000000000000000000000000000000000007", + "b0e6add595e00477cf347d09797b156719dc5233283ac76e4efce2a674fe72d9", + {}, + TransactionSettlementEvent.NONE, + ), ( "0000000000000000000000000000000000000000000000000000000000000002", "b0e6add595e00477cf347d09797b156719dc5233283ac76e4efce2a674fe72d9", @@ -771,6 +785,7 @@ def test_run( test_round = CheckTransactionHistoryRound( synchronized_data=self.synchronized_data, + context=MagicMock(), ) self._complete_run( @@ -833,6 +848,7 @@ def test_runs( self.synchronized_data.update(missed_messages=missed_messages) test_round = SynchronizeLateMessagesRound( synchronized_data=self.synchronized_data, + context=MagicMock(), ) late_arriving_tx_hashes = { p: "".join(("1" * TX_HASH_LENGTH, "2" * TX_HASH_LENGTH)) @@ -865,6 +881,7 @@ def test_check_payload(self, correct_serialization: bool) -> None: test_round = SynchronizeLateMessagesRound( synchronized_data=self.synchronized_data, + context=MagicMock(), ) sender = list(test_round.accepting_payloads_from).pop() hash_length = TX_HASH_LENGTH @@ -987,7 +1004,10 @@ def test_runs( synchronized_data._db._cross_period_persisted_keys = frozenset( {"most_voted_randomness"} ) - test_round = ResetRound(synchronized_data=synchronized_data) + test_round = ResetRound( + synchronized_data=synchronized_data, + context=MagicMock(), + ) next_period_count = 1 self._complete_run( self._test_round( diff --git a/plugins/aea-test-autonomy/aea_test_autonomy/base_test_classes/agents.py b/plugins/aea-test-autonomy/aea_test_autonomy/base_test_classes/agents.py index 63a7eb1856..056d65dde2 100644 --- a/plugins/aea-test-autonomy/aea_test_autonomy/base_test_classes/agents.py +++ b/plugins/aea-test-autonomy/aea_test_autonomy/base_test_classes/agents.py @@ -172,7 +172,7 @@ def __set_configs(self, i: int, nb_agents: int) -> None: f"vendor.{skill.author}.skills.{skill.name}.models.params.args.setup.all_participants", json.dumps( [ - Web3.toChecksumAddress(pairs[0]) + Web3.to_checksum_address(pairs[0]) for pairs in key_pairs[:nb_agents] ] ), @@ -385,7 +385,10 @@ def check_aea_messages(self) -> None: for i, process in self.processes.items(): if i in self.exclude_from_checks: continue - (missing_strict_strings, missing_round_strings,) = self.missing_from_output( + ( + missing_strict_strings, + missing_round_strings, + ) = self.missing_from_output( process=process, happy_path=self.happy_path, strict_check_strings=self.strict_check_strings, diff --git a/plugins/aea-test-autonomy/aea_test_autonomy/configurations.py b/plugins/aea-test-autonomy/aea_test_autonomy/configurations.py index 634b833a6c..1ea7b63aff 100644 --- a/plugins/aea-test-autonomy/aea_test_autonomy/configurations.py +++ b/plugins/aea-test-autonomy/aea_test_autonomy/configurations.py @@ -37,7 +37,7 @@ def get_key(key_path: Path) -> str: HTTP_LOCALHOST = f"http://{LOCALHOST}" DEFAULT_IMAGE_VERSION = "latest" -MATCHING_FRAMEWORK_VERSION = "0.10.2" +MATCHING_FRAMEWORK_VERSION = "0.13.9.post1" TENDERMINT_IMAGE_VERSION = os.environ.get( "TENDERMINT_IMAGE_VERSION", MATCHING_FRAMEWORK_VERSION ) diff --git a/plugins/aea-test-autonomy/aea_test_autonomy/docker/registries.py b/plugins/aea-test-autonomy/aea_test_autonomy/docker/registries.py index 0933cc7bca..b0ffa91101 100644 --- a/plugins/aea-test-autonomy/aea_test_autonomy/docker/registries.py +++ b/plugins/aea-test-autonomy/aea_test_autonomy/docker/registries.py @@ -33,20 +33,26 @@ DEFAULT_HARDHAT_PORT = 8545 REGISTRIES_CONTRACTS_DIR = "autonolas-registries" -DEFAULT_ACCOUNT = "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" -COMPONENT_REGISTRY = "0x5FbDB2315678afecb367f032d93F642f64180aa3" -AGENT_REGISTRY = "0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512" -REGISTRIES_MANAGER = "0x9fE46736679d2D9a65F0992F2272dE9f3c7fa6e0" -GNOSIS_SAFE_MULTISIG = "0xA51c1fc2f0D1a1b8494Ed1FE312d7C3a78Ed91C0" -SERVICE_REGISTRY = "0x998abeb3E57409262aE5b751f60747921B33613E" -SERVICE_MANAGER = "0x70e0bA845a1A0F2DA3359C97E0285013525FFC49" -GNOSIS_SAFE_MASTER_COPY = "0x4826533B4897376654Bb4d4AD88B7faFD0C98528" -GNOSIS_SAFE_PROXY_FACTORY = "0x99bbA657f2BbC93c02D617f8bA121cB8Fc104Acf" -GNOSIS_SAFE_MULTISIG = "0x0E801D84Fa97b50751Dbf25036d067dCf18858bF" -GNOSIS_SAFE_MULTISIG_WITH_SAME_ADDRESS = "0x8f86403A4DE0BB5791fa46B8e795C547942fE4Cf" -GNOSIS_SAFE_MULTISEND = "0x9d4454B023096f34B160D6B654540c56A1F81688" -SERVICE_MULTISIG_1 = "0xD8dE647170163a981bb3Fdb2063583eAcF7D55AC" -SERVICE_MULTISIG_2 = "0x070fC9F640b0cC01ab0159d23f09f8936077C9e9" +DEFAULT_ACCOUNT = "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" # nosec +COMPONENT_REGISTRY = "0x5FbDB2315678afecb367f032d93F642f64180aa3" # nosec +AGENT_REGISTRY = "0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512" # nosec +REGISTRIES_MANAGER = "0x9fE46736679d2D9a65F0992F2272dE9f3c7fa6e0" # nosec +GNOSIS_SAFE_MULTISIG = "0x0E801D84Fa97b50751Dbf25036d067dCf18858bF" # nosec +SERVICE_REGISTRY = "0x998abeb3E57409262aE5b751f60747921B33613E" # nosec +SERVICE_REGISTRY_TOKEN_UTILITY = "0x36C02dA8a0983159322a80FFE9F24b1acfF8B570" # nosec +SERVICE_MANAGER_TOKEN = "0x4c5859f0F772848b2D91F1D83E2Fe57935348029" # nosec +SERVICE_REGISTRY_L2 = "0x5eb3Bc0a489C5A8288765d2336659EbCA68FCd00" # nosec +SERVICE_MANAGER = "0x70e0bA845a1A0F2DA3359C97E0285013525FFC49" # nosec +OPERATOR_WHITELIST = "0x809d550fca64d94Bd9F66E60752A544199cfAC3D" # nosec +ERC20_TOKEN = "0x1291Be112d480055DaFd8a610b7d1e203891C274" # nosec +GNOSIS_SAFE_MASTER_COPY = "0x4826533B4897376654Bb4d4AD88B7faFD0C98528" # nosec +GNOSIS_SAFE_PROXY_FACTORY = "0x99bbA657f2BbC93c02D617f8bA121cB8Fc104Acf" # nosec +GNOSIS_SAFE_MULTISIG_WITH_SAME_ADDRESS = ( + "0x8f86403A4DE0BB5791fa46B8e795C547942fE4Cf" # nosec +) +GNOSIS_SAFE_MULTISEND = "0x9d4454B023096f34B160D6B654540c56A1F81688" # nosec +SERVICE_MULTISIG_1 = "0x77b783e911F4398D75908Cc60C7138Bd1eFe35Fd" # nosec +SERVICE_MULTISIG_2 = "0x89CB72532402144C3f4dbF61ed9b0779E30091F5" # nosec DEFAULT_SERVICE_CONFIG_HASH = ( "0xd913b5bf68193dfacb941538d5900466c449c9ec8121153f152de2e026fa7f3a" ) diff --git a/plugins/aea-test-autonomy/setup.py b/plugins/aea-test-autonomy/setup.py index 8655b731e0..d23fbadbaf 100644 --- a/plugins/aea-test-autonomy/setup.py +++ b/plugins/aea-test-autonomy/setup.py @@ -24,15 +24,15 @@ base_deps = [ - "open-aea[all]>=1.32.0,<2.0.0", + "open-aea[all]>=1.43.0.post2,<2.0.0", "pytest==7.2.1", - "open-aea-ledger-ethereum==1.32.0", - "docker==6.0.0", + "open-aea-ledger-ethereum>=1.43.0.post2,<2.0.0", + "docker==6.1.2", ] setup( name="open-aea-test-autonomy", - version="0.10.2", + version="0.13.9.post1", author="Valory AG", license="Apache-2.0", description="Plugin containing test tools for open-autonomy packages.", @@ -59,10 +59,10 @@ "Operating System :: MacOS", "Operating System :: Microsoft", "Operating System :: Unix", - "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", "Topic :: Communications", "Topic :: Internet", "Topic :: Software Development", diff --git a/plugins/aea-test-autonomy/tests/test_base_test_classes/test_agents.py b/plugins/aea-test-autonomy/tests/test_base_test_classes/test_agents.py index acba8d2e76..b241253e25 100644 --- a/plugins/aea-test-autonomy/tests/test_base_test_classes/test_agents.py +++ b/plugins/aea-test-autonomy/tests/test_base_test_classes/test_agents.py @@ -138,7 +138,7 @@ def test_test_run_incorrect_agent_package(self) -> None: with pytest.raises(click.exceptions.ClickException, match=expected): test_instance.test_run(nb_nodes) - wrong_version = "valory/hello_world:0.0.0" + wrong_version = "valory/offend_slash:0.0.0" expected = "Wrong agent version in public ID: specified 0.0.0, found" setattr(test_instance, attribute, wrong_version) with pytest.raises(click.exceptions.ClickException, match=expected): @@ -151,13 +151,13 @@ def test_test_run_incorrect_skill_package(self) -> None: test_instance = self.setup_test() self.set_mocked_flask_tendermint_image(test_instance, nb_nodes) - test_instance.agent_package = "valory/hello_world:0.1.0" + test_instance.agent_package = "valory/offend_slash:0.1.0" attribute = "skill_package" with pytest.raises(AttributeError, match=f"has no attribute '{attribute}'"): test_instance.test_run(nb_nodes) - for item in ("", "author/package", "valory/hello_world:0.0.0"): + for item in ("", "author/package", "valory/offend_abci:0.0.0"): setattr(test_instance, attribute, item) # same for "author/package" expected = 'Item "agent_00000" already exists in target folder "."' with pytest.raises(click.exceptions.ClickException, match=expected): @@ -171,8 +171,8 @@ def test_test_run_with_agent(self) -> None: self.set_mocked_flask_tendermint_image(test_instance, nb_nodes) test_instance.wait_to_finish = mock.Mock() - test_instance.agent_package = "valory/hello_world:0.1.0" - test_instance.skill_package = "valory/hello_world_abci:0.1.0" + test_instance.agent_package = "valory/offend_slash:0.1.0" + test_instance.skill_package = "valory/offend_abci:0.1.0" mocked_missing_from_output = as_context( mock.patch.object( @@ -183,6 +183,7 @@ def test_test_run_with_agent(self) -> None: ), ) + test_instance.ipfs_domain = "" with mock.patch.object(test_instance, "run_agent") as mocked_run_agent: with mock.patch.object( test_instance, "health_check" diff --git a/pytest.ini b/pytest.ini deleted file mode 100644 index aa2c25ceee..0000000000 --- a/pytest.ini +++ /dev/null @@ -1,17 +0,0 @@ -[pytest] -log_cli = 1 -log_cli_level = DEBUG -log_cli_format = %(asctime)s [%(levelname)8s] %(message)s (%(filename)s:%(lineno)s) -log_cli_date_format=%Y-%m-%d %H:%M:%S - -markers = - integration: marks integration tests which require other network services - e2e: marks end-to-end agent tests - - -filterwarnings = - ignore::DeprecationWarning:aea.*: - ignore::DeprecationWarning - ignore:.*MismatchedABI - ignore:.*cannot collect test class 'TestAbciApp' - ignore:.*cannot collect test class 'TestAbciConsensusBehaviour diff --git a/scripts/RELEASE_PROCESS.md b/scripts/RELEASE_PROCESS.md index 55771012cd..ddc3e3c69a 100644 --- a/scripts/RELEASE_PROCESS.md +++ b/scripts/RELEASE_PROCESS.md @@ -22,7 +22,7 @@ 9. Write release notes and place them in `HISTORY.md`. Add upgrading tips in `upgrading.md`. If necessary, adjust version references in `SECURITY.md`. Commit if satisfied. -10. Run spell checker `./scripts/spell-check.sh`. Run `pylint --disable all --enable spelling ...`. Commit if required. +10. Run spell checker `tomte check-spelling`. Run `pylint --disable all --enable spelling ...`. Commit if required. 11. Open PRs and merge into develop. Then open develop to main PR and merge it. diff --git a/scripts/bump.py b/scripts/bump.py new file mode 100644 index 0000000000..2a864cf5c8 --- /dev/null +++ b/scripts/bump.py @@ -0,0 +1,297 @@ +""" +Script for bumping core dependencies. + +This script + +- Fetches the latest core dependency versions from github +- Updates the tox.ini, packages and Pipfile/pyproject.toml files +- Performs the packages sync +""" + +import os +import re +import typing as t +from pathlib import Path + +import click +import requests +from aea.cli.utils.click_utils import PackagesSource, PyPiDependency +from aea.configurations.constants import PACKAGES, PACKAGE_TYPE_TO_CONFIG_FILE +from aea.configurations.data_types import Dependency +from aea.helpers.logging import setup_logger +from aea.helpers.yaml_utils import yaml_dump, yaml_dump_all, yaml_load, yaml_load_all +from aea.package_manager.v1 import PackageManagerV1 + +from autonomy.cli.helpers.ipfs_hash import load_configuration + + +BUMP_BRANCH = "chore/bump" +PIPFILE = Path.cwd() / "Pipfile" +PYPROJECT_TOML = Path.cwd() / "pyproject.toml" +TOX_INI = Path.cwd() / "tox.ini" + +TAGS_URL = "https://api.github.com/repos/{repo}/tags" +FILE_URL = "https://raw.githubusercontent.com/{repo}/{tag}/{file}" + +VERISON_RE = re.compile(r"(__version__|version)( )?=( )?\"(?P[0-9a-z\.]+)\"") + +OPEN_AEA_REPO = "valory-xyz/open-aea" +OPEN_AUTONOMY_REPO = "valory-xyz/open-autonomy" + +DEPENDENCY_SPECS = { + "open-aea": { + "repo": OPEN_AEA_REPO, + "file": "aea/__version__.py", + }, + "open-aea-ledger-ethereum": { + "repo": OPEN_AEA_REPO, + "file": "plugins/aea-ledger-ethereum/setup.py", + }, + "open-aea-ledger-ethereum-flashbots": { + "repo": OPEN_AEA_REPO, + "file": "plugins/aea-ledger-ethereum-flashbots/setup.py", + }, + "open-aea-ledger-ethereum-hwi": { + "repo": OPEN_AEA_REPO, + "file": "plugins/aea-ledger-ethereum-hwi/setup.py", + }, + "open-aea-ledger-cosmos": { + "repo": OPEN_AEA_REPO, + "file": "plugins/aea-ledger-cosmos/setup.py", + }, + "open-aea-ledger-solana": { + "repo": OPEN_AEA_REPO, + "file": "plugins/aea-ledger-solana/setup.py", + }, + "open-aea-cli-ipfs": { + "repo": OPEN_AEA_REPO, + "file": "plugins/aea-cli-ipfs/setup.py", + }, + "open-autonomy": { + "repo": OPEN_AUTONOMY_REPO, + "file": "autonomy/__version__.py", + }, + "open-aea-test-autonomy": { + "repo": OPEN_AUTONOMY_REPO, + "file": "plugins/aea-test-autonomy/setup.py", + }, +} + +_cache_file = Path.home() / ".aea" / ".gitcache" +_version_cache = {} +_logger = setup_logger("bump") + + +def load_git_cache() -> None: + """Load versions cache.""" + if not _cache_file.exists(): + return + with _cache_file.open("r", encoding="utf-8") as stream: + _version_cache.update(yaml_load(stream=stream)) + + +def dump_git_cache() -> None: + """Dump versions cache.""" + with _cache_file.open("w", encoding="utf-8") as stream: + yaml_dump(data=_version_cache, stream=stream) + + +def make_git_request(url: str) -> requests.Response: + """Make git request""" + auth = os.environ.get("GITHUB_AUTH") + if auth is None: + return requests.get(url=url) + return requests.get(url=url, headers={"Authorization": f"Bearer {auth}"}) + + +def get_latest_tag(repo: str) -> str: + """Fetch latest git tag.""" + if repo in _version_cache: + return _version_cache[repo] + + response = make_git_request(url=TAGS_URL.format(repo=repo)) + if response.status_code != 200: + raise ValueError( + f"Fetching tags from `{repo}` failed with message '" + + response.json()["message"] + + "'" + ) + latest_tag_data, *_ = response.json() + _version_cache[repo] = latest_tag_data["name"] + return _version_cache[repo] + + +def get_dependency_version(repo: str, file: str) -> str: + """Get version spec .""" + response = make_git_request( + FILE_URL.format( + repo=repo, + tag=get_latest_tag(repo=repo), + file=file, + ) + ) + if response.status_code != 200: + raise ValueError( + f"Fetching packages from `{repo}` failed with message '" + + response.text + + "'" + ) + ((*_, version),) = VERISON_RE.findall(response.content.decode()) + return f"=={version}" + + +def get_dependencies() -> t.Dict: + """Get dependency->version mapping.""" + dependencies = {} + for dependency, specs in DEPENDENCY_SPECS.items(): + version = _version_cache.get( + dependency, + get_dependency_version( + repo=specs["repo"], + file=specs["file"], + ), + ) + dependencies[dependency] = version + _version_cache.update(dependencies) + return dependencies + + +def bump_pipfile_or_pyproject(file: Path, dependencies: t.Dict[str, str]) -> None: + """Bump Pipfile.""" + if not file.exists(): + return + + _logger.info(f"Updating {file.name}") + updated = "" + content = file.read_text(encoding="utf-8") + for line in content.split("\n"): + try: + spec = Dependency.from_pipfile_string(line) + update = dependencies.get(spec.name) + if update is None: + updated += line + "\n" + continue + spec = Dependency( + name=spec.name, + version=update, + extras=spec.extras, + ) + updated += spec.to_pipfile_string() + "\n" + except ValueError: + updated += line + "\n" + file.write_text(updated[:-1], encoding="utf-8") + + +def bump_tox(dependencies: t.Dict[str, str]) -> None: + """Bump tox file.""" + if not TOX_INI.exists(): + return + + _logger.info("Updating tox.ini") + updated = "" + content = TOX_INI.read_text(encoding="utf-8") + for line in content.split("\n"): + try: + spec = Dependency.from_string(line.lstrip().rstrip()) + update = dependencies.get(spec.name) + if update is None: + updated += line + "\n" + continue + spec = Dependency( + name=spec.name, + version=update, + extras=spec.extras, + ) + updated += " " + spec.to_pip_string() + "\n" + except ValueError: + updated += line + "\n" + TOX_INI.write_text(updated[:-1], encoding="utf-8") + + +def bump_packages(dependencies: t.Dict[str, str]) -> None: + """Bump packages.""" + _logger.info("Updating packages") + manager = PackageManagerV1.from_dir(Path(PACKAGES)) + for package_id in manager.dev_packages: + path = ( + manager.package_path_from_package_id( + package_id=package_id, + ) + / PACKAGE_TYPE_TO_CONFIG_FILE[package_id.package_type.value] + ) + with path.open("r", encoding="utf-8") as stream: + config, *extra = yaml_load_all(stream=stream) + + for name in config.get("dependencies", {}): + update = dependencies.get(name) + if update is None: + continue + config["dependencies"][name]["version"] = update + + with path.open("w", encoding="utf-8") as stream: + yaml_dump_all([config, *extra], stream=stream) + + +@click.command(name="bump") +@click.option( + "-d", + "--dependency", + "extra", + type=PyPiDependency(), + multiple=True, + help="Specify extra dependency.", +) +@click.option( + "-s", + "--source", + "sources", + type=PackagesSource(), + multiple=True, + help="Specify extra sources.", +) +@click.option("--sync", is_flag=True, help="Perform sync.") +@click.option( + "--no-cache", + is_flag=True, + default=False, + help="Avoid using cache to bump.", +) +def main( + extra: t.Tuple[Dependency, ...], + sources: t.Tuple[str, ...], + sync: bool, + no_cache: bool, +) -> None: + """Run the bump script.""" + + if not no_cache: + load_git_cache() + + dependencies = {} + dependencies.update(get_dependencies()) + dependencies.update({dep.name: dep.version for dep in extra or []}) + + bump_pipfile_or_pyproject(PIPFILE, dependencies=dependencies) + bump_pipfile_or_pyproject(PYPROJECT_TOML, dependencies=dependencies) + bump_tox(dependencies=dependencies) + bump_packages(dependencies=dependencies) + dump_git_cache() + + if sync: + pm = PackageManagerV1.from_dir( + Path.cwd() / PACKAGES, config_loader=load_configuration + ) + pm.sync( + sources=[ + f"{OPEN_AEA_REPO}:{_version_cache[OPEN_AEA_REPO]}", + f"{OPEN_AUTONOMY_REPO}:{_version_cache[OPEN_AUTONOMY_REPO]}", + *sources, + ], + update_packages=True, + ) + pm.update_package_hashes() + pm.dump() + + +if __name__ == "__main__": + main() # pylint: disable=no-value-for-parameter diff --git a/scripts/check_copyright.py b/scripts/check_copyright.py index a667fa8cfa..36170f1ae3 100755 --- a/scripts/check_copyright.py +++ b/scripts/check_copyright.py @@ -163,7 +163,6 @@ def _validate_years( # Specified year is 2021/2022 but the file has been last modified in another later year (missing -202x) if end_year is not None and check_end_year: - if start_year > end_year: check_info["check"] = False check_info["message"] = "End year should be greater then start year." diff --git a/scripts/check_dependencies.py b/scripts/check_dependencies.py new file mode 100755 index 0000000000..a8a165db67 --- /dev/null +++ b/scripts/check_dependencies.py @@ -0,0 +1,199 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +# ------------------------------------------------------------------------------ +# +# Copyright 2022-2023 Valory AG +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# ------------------------------------------------------------------------------ +""" +This script checks that the pipfile of the repository meets the requirements. + +In particular: +- Avoid the usage of "*" + +It is assumed the script is run from the repository root. +""" + +import os +import subprocess # nosec +import sys +from pathlib import Path +from typing import Any, Dict + +import toml +from aea.configurations.data_types import Dependency, PackageType +from aea.package_manager.base import load_configuration +from aea.package_manager.v1 import PackageManagerV1 + + +def load_pipfile(pipfile_path: str = "./Pipfile") -> dict: + """Load the Pipfile file contents.""" + + # Load the Pipfile file + with open(pipfile_path, "r", encoding="utf-8") as toml_file: + toml_data = toml.load(toml_file) + + # Get the [dev-packages] section + dependencies = toml_data.get("dev-packages", {}) + dependencies.update(toml_data.get("packages", {})) + + return dependencies + + +def get_package_dependencies() -> Dict[str, Any]: + """Returns a list of package dependencies.""" + package_manager = PackageManagerV1.from_dir( + Path(os.environ.get("PACKAGES_DIR", str(Path.cwd() / "packages"))) + ) + dependencies: Dict[str, Dependency] = {} + for package in package_manager.iter_dependency_tree(): + if package.package_type == PackageType.SERVICE: + continue + _dependencies = load_configuration( + package_type=package.package_type, + package_path=package_manager.package_path_from_package_id( + package_id=package + ), + ).dependencies + for key, value in _dependencies.items(): + if key not in dependencies: + dependencies[key] = value + else: + if value.version == "": + continue + if dependencies[key].version == "": + dependencies[key] = value + elif value == dependencies[key]: + continue + else: + print( + f"Non-matching dependency versions for {key}: {value} vs {dependencies[key]}" + ) + + return {package.name: package.version for package in dependencies.values()} + + +def warnings(listed_package_dependencies: dict, new_package_dependencies: dict) -> None: + """Warn about mismatches.""" + + for key, value in new_package_dependencies.items(): + if key in ["open-aea-test-autonomy"]: + continue + if key not in listed_package_dependencies: + print(f"Package {key} not found in Pipfile") + sys.exit(1) + if ( + key in listed_package_dependencies + and value == "" + and listed_package_dependencies[key] == "*" + ): + continue + if ( + key in listed_package_dependencies + and value != listed_package_dependencies[key] + ): + print( + f"Package {key} has version {listed_package_dependencies[key]} in Pipfile and {value} in packages." + ) + sys.exit(1) + + +def update_tox_ini( + new_package_dependencies: dict, tox_ini_path: str = "./tox.ini" +) -> None: + """Update the tox.ini file with the new package dependencies.""" + for key, value in new_package_dependencies.items(): + if isinstance(value, str) and len(value) == 1 and "*" == value[0]: + new_package_dependencies[key] = "" + if isinstance(value, dict): + if "extras" in value: + value_ = "[" + for it in value["extras"]: + value_ += it + value_ += "," + value_ = value_[:-1] + value_ += "]" + new_package_dependencies[key] = value_ + value["version"] + elif "git" in value: + new_package_dependencies[key] = ( + "git+" + + value["git"] + + "@" + + value.get("ref", "None") + + "#egg=" + + key + ) + else: + raise ValueError(value) + with open(tox_ini_path, "r", encoding="utf-8") as file: + lines = file.readlines() + + # Find the [deps-packages] section and replace the deps value + start_line = None + end_line = None + for i, line in enumerate(lines): + if line.strip() == "[deps-packages]": + start_line = i + 1 + break + + if start_line is not None: + for i in range(start_line, len(lines)): + if lines[i].strip().startswith("["): + end_line = i + break + else: + end_line = len(lines) + + updated_lines = ["deps =\n"] + [" {[deps-tests]deps}\n"] + for key, value in new_package_dependencies.items(): + if str(value).startswith("git+"): + updated_lines.append(f" {value}\n") + else: + updated_lines.append(f" {key}{value}\n") + updated_lines.extend(["\n"]) + + lines[start_line:end_line] = updated_lines + + # Write the modified content back to the tox.ini file + with open(tox_ini_path, "w", encoding="utf-8") as file: + file.writelines(lines) + + +def check_for_no_changes( + pyproject_toml_path: str = "./pyproject.toml", tox_ini_path: str = "./tox.ini" +) -> bool: + """Check if there are any changes in the current repository.""" + + # Check if there are any changes + result = subprocess.run( # pylint: disable=W1510 # nosec + ["git", "diff", "--quiet", "--", pyproject_toml_path, tox_ini_path], + capture_output=True, + text=True, + ) + + return result.returncode == 0 + + +if __name__ == "__main__": + update = len(sys.argv[1:]) > 0 + package_dependencies = get_package_dependencies() + listed_package_dependencies_ = load_pipfile() + warnings(listed_package_dependencies_, package_dependencies) + update_tox_ini(listed_package_dependencies_) + if not update and not check_for_no_changes(): + print( + "There are mismatching package dependencies in the pyproject.toml file and the packages." + ) + sys.exit(1) diff --git a/scripts/check_doc_ipfs_hashes.py b/scripts/check_doc_ipfs_hashes.py index bc9beb43aa..82af4a4eb2 100755 --- a/scripts/check_doc_ipfs_hashes.py +++ b/scripts/check_doc_ipfs_hashes.py @@ -23,12 +23,12 @@ import argparse import itertools -import json import re import sys from pathlib import Path from typing import Dict, List, Optional +import requests import yaml from aea.cli.packages import get_package_manager from aea.configurations.data_types import PackageId @@ -50,9 +50,13 @@ AEA_COMMAND_REGEX = rf"(?P{CLI_REGEX} {CMD_REGEX} (?:{VENDOR_REGEX}\/{PACKAGE_REGEX}:{VERSION_REGEX}?:?)?(?P{IPFS_HASH_REGEX}){FLAGS_REGEX})" FULL_PACKAGE_REGEX = rf"(?P(?:{VENDOR_REGEX}\/{PACKAGE_REGEX}:{VERSION_REGEX}?:?)?(?P{IPFS_HASH_REGEX}))" PACKAGE_TABLE_REGEX = rf"\|\s*{PACKAGE_TYPE_REGEX}\/{VENDOR_REGEX}\/{PACKAGE_REGEX}\/{VERSION_REGEX}\s*\|\s*`(?P{IPFS_HASH_REGEX})`\s*\|" +PACKAGE_MAPPING_REGEX = rf"(?P(?:\"{PACKAGE_TYPE_REGEX}\/{VENDOR_REGEX}\/{PACKAGE_REGEX}\/{VERSION_REGEX}\":)\s*\"(?P{IPFS_HASH_REGEX})\")" ROOT_DIR = Path(__file__).parent.parent -HASH_SKIPS = ["Qmbh9SQLbNRawh9Km3PMEDSxo77k1wib8fYZUdZkhPBiev"] +HASH_SKIPS = [ + "Qmbh9SQLbNRawh9Km3PMEDSxo77k1wib8fYZUdZkhPBiev", # Testing image used in tutorials/examples. + "bafybei0000000000000000000000000000000000000000000000000000", # Placeholder hash used in tutorials/examples. +] def read_file(filepath: str) -> str: @@ -70,10 +74,40 @@ def get_packages() -> Dict[str, str]: return data +def get_packages_from_repository(repo_url: str) -> Dict[str, str]: + """Retrieve packages.json from the latest release from a repository.""" + repo_url = repo_url.strip("/").replace("https://github.com/", "") + repo_api_url = f"https://api.github.com/repos/{repo_url}/releases/latest" + response = requests.get(repo_api_url) + + if response.status_code == 200: + repo_info = response.json() + latest_release_tag = repo_info["tag_name"] + url = f"https://raw.githubusercontent.com/{repo_url}/{latest_release_tag}/packages/packages.json" + else: + raise Exception( + f"Failed to fetch repository information from GitHub API for: {repo_url}" + ) + + response = requests.get(url) + if response.status_code == 200: + data = response.json() + if "dev" in data: + return {**data["dev"], **data["third_party"]} + return data + + raise Exception(f"Failed to fetch data from URL: {url}") + + class Package: # pylint: disable=too-few-public-methods """Class that represents a package in packages.json""" - def __init__(self, package_id_str: str, package_hash: str) -> None: + def __init__( + self, + package_id_str: str, + package_hash: str, + ignore_file_load_errors: bool = False, + ) -> None: """Constructor""" self.package_id = PackageId.from_uri_path(package_id_str) @@ -81,6 +115,7 @@ def __init__(self, package_id_str: str, package_hash: str) -> None: self.type = self.package_id.package_type.to_plural() self.name = self.package_id.name self.hash = package_hash + self.ignore_file_load_errors = ignore_file_load_errors if self.name == "scaffold": return @@ -107,12 +142,18 @@ def __init__(self, package_id_str: str, package_hash: str) -> None: self.name, f"{'aea-config' if self.type == 'agent' else self.type}.yaml", ) - with open(yaml_file_path, "r", encoding="utf-8") as file: - content = yaml.load_all(file, Loader=yaml.FullLoader) - for resource in content: - if "version" in resource: - self.last_version = resource["version"] - break + + try: + with open(yaml_file_path, "r", encoding="utf-8") as file: + content = yaml.load_all(file, Loader=yaml.FullLoader) + for resource in content: + if "version" in resource: + self.last_version = resource["version"] + break + except Exception: # pylint: disable=broad-except + if not self.ignore_file_load_errors: + raise + self.last_version = self.package_id.version def get_command( self, cmd: str, include_version: bool = True, flags: str = "" @@ -139,6 +180,17 @@ def __init__(self) -> None: packages = get_packages() self.packages = [Package(key, value) for key, value in packages.items()] + package_json_urls = [ + "https://github.com/valory-xyz/hello-world", + ] + + for url in package_json_urls: + packages_from_url = get_packages_from_repository(url) + packages.update(packages_from_url) + self.packages.extend( + [Package(key, value, True) for key, value in packages_from_url.items()] + ) + self.package_tree: Dict = {} for p in self.packages: self.package_tree.setdefault(p.vendor, {}) @@ -240,38 +292,6 @@ def get_hash_by_attributes( return self.package_tree[vendor][package_type][package_name].hash -def update_set_up(fix: bool = False) -> None: - """Update `set_up.md` file.""" - md_file = Path("docs", "guides", "set_up.md") - packages: Dict[str, Dict[str, str]] = json.loads( - Path("packages", "packages.json").read_text(encoding="utf-8") - ) - package_hash_str_re = re.compile( - r"(\"([a-z_0-9]+/[a-z_0-9]+/[a-z_0-9]+/[0-9.]+)\": \"(bafybei[0-9a-z]+)\")" - ) - md_file_content = md_file.read_text(encoding="utf-8") - for match in package_hash_str_re.findall(md_file_content): - line, package_name, package_hash = match - package_hash_update = packages.get("dev", {}).get( - package_name, packages.get("third_party", {}).get(package_name) - ) - if package_hash == package_hash_update: - continue - if not fix: - print( - f"Package hash does not match in `docs/guides/set_up.md` file" - f"\n\tPackage name: {package_name}" - f"\n\tHash in file: {package_hash}" - f"\n\tHash in `packages.json`: {package_hash_update}" - ) - sys.exit(1) - - line_update = line.replace(package_hash, package_hash_update) - md_file_content = md_file_content.replace(line, line_update) - - md_file.write_text(md_file_content, encoding="utf-8") - - def check_ipfs_hashes( # pylint: disable=too-many-locals,too-many-statements paths: Optional[List[Path]] = None, fix: bool = False ) -> None: @@ -286,9 +306,11 @@ def check_ipfs_hashes( # pylint: disable=too-many-locals,too-many-statements package_manager = PackageHashManager() matches = 0 - # Fix full commands in docs + # Fix hashes in docs for md_file in all_md_files: content = read_file(str(md_file)) + + # Fix full commands in docs for match in [m.groupdict() for m in re.finditer(AEA_COMMAND_REGEX, content)]: matches += 1 doc_full_cmd = match["full_cmd"] @@ -333,6 +355,44 @@ def check_ipfs_hashes( # pylint: disable=too-many-locals,too-many-statements f"\tFound: {doc_hash}\n" ) + # Fix package mappings in docs + for match in [ + m.groupdict() for m in re.finditer(PACKAGE_MAPPING_REGEX, content) + ]: + matches += 1 + package_mapping = match["package_mapping"] + package_hash = match["hash"] + + if package_hash in HASH_SKIPS: + continue + + expected_hash = package_manager.get_hash_by_attributes( + match["package_type"], match["vendor"], match["package"] + ) + + if package_hash == expected_hash: + continue + + hash_mismatches = True + + if fix: + new_package_mapping = package_mapping.replace( + package_hash, expected_hash + ) + content = content.replace(package_mapping, new_package_mapping) + + with open(str(md_file), "w", encoding="utf-8") as qs_file: + qs_file.write(content) + print(f"Fixed an IPFS hash in doc file {md_file}") + old_to_new_hashes[package_hash] = expected_hash + else: + print( + f"IPFS hash mismatch in doc file {md_file}.\n" + f"\tMapping string: {package_mapping}\n" + f"\tExpected: {expected_hash}\n" + f"\tFound: {package_hash}\n" + ) + # Fix packages in python files all_py_files = [Path("autonomy", "constants.py")] for py_file in all_py_files: @@ -419,8 +479,6 @@ def check_ipfs_hashes( # pylint: disable=too-many-locals,too-many-statements ) sys.exit(1) - update_set_up(fix=fix) - print("Checking doc IPFS hashes finished successfully.") diff --git a/scripts/check_doc_links.py b/scripts/check_doc_links.py index 7d3ffee0af..4ce81888db 100755 --- a/scripts/check_doc_links.py +++ b/scripts/check_doc_links.py @@ -57,6 +57,7 @@ "https://gateway.autonolas.tech/ipfs/,", # non link (400) "https://github.com/valory-xyz/open-autonomy/trunk/infrastructure", # svn link (404) "http://host.docker.internal:8545", # internal (ERR_NAME_NOT_RESOLVED) + "https://github.com/valory-xyz/open-operator", # Until public ] # Define here custom timeouts for some edge cases @@ -89,7 +90,6 @@ def check_file( broken_links = [] for url in m: - # Add the closing parenthesis if it is missing, as the REGEX is too strict sometimes if "(" in url and ")" not in url: url += ")" diff --git a/scripts/check_pipfiles.py b/scripts/check_pipfiles.py deleted file mode 100755 index 9516d53ce4..0000000000 --- a/scripts/check_pipfiles.py +++ /dev/null @@ -1,60 +0,0 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- -# ------------------------------------------------------------------------------ -# -# Copyright 2022 Valory AG -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -# ------------------------------------------------------------------------------ -""" -This script checks that the pipfile of the repository meets the requirements. - -In particular: -- Avoid the usage of "*" - -It is assumed the script is run from the repository root. -""" -import re -import sys -from pathlib import Path - - -UNPINNED_PACKAGE_REGEX = r'(?P.*)\s?=\s?"\*"' - - -def check_pipfile(pipfile_path: Path) -> bool: - """Check a Pipfile""" - - print(f"Checking {pipfile_path.joinpath()}... ", end="") - with open(pipfile_path, "r", encoding="utf-8") as pipfile: - lines = pipfile.readlines() - unpinned = [] - for line in lines: - m = re.match(UNPINNED_PACKAGE_REGEX, line) - if m: - unpinned.append(m.groupdict()["package_name"]) - if unpinned: - print( - f"\nThe packages {unpinned} have not been pinned in {pipfile_path.joinpath()}" - ) - return False - print("OK") - return True - - -if __name__ == "__main__": - root_path = Path(".") - for file_path in root_path.rglob("*Pipfile*"): - if not check_pipfile(pipfile_path=file_path): - sys.exit(1) diff --git a/scripts/generate_api_documentation.py b/scripts/generate_api_documentation.py index c1c224bfcd..8c0e3f0c32 100755 --- a/scripts/generate_api_documentation.py +++ b/scripts/generate_api_documentation.py @@ -2,7 +2,7 @@ # -*- coding: utf-8 -*- # ------------------------------------------------------------------------------ # -# Copyright 2021-2022 Valory AG +# Copyright 2021-2023 Valory AG # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -24,6 +24,7 @@ import shutil import subprocess # nosec import sys +from concurrent.futures import ThreadPoolExecutor from pathlib import Path from typing import Set @@ -127,7 +128,7 @@ def should_skip(module_path: Path) -> bool: return False -def _generate_apidocs_aea_modules() -> None: +def _generate_apidocs_aea_modules(executor: ThreadPoolExecutor) -> None: """Generate API docs for aea.* modules.""" for module_path in filter(is_not_dir, Path(AEA_DIR).rglob("*")): print(f"Processing {module_path}... ", end="") @@ -138,10 +139,10 @@ def _generate_apidocs_aea_modules() -> None: last = module_path.stem doc_file = API_DIR / Path(*parents_without_root) / f"{last}.md" dotted_path = ".".join(parents) + "." + last - make_pydoc(dotted_path, doc_file) + executor.submit(make_pydoc, dotted_path, doc_file) -def _generate_apidocs_packages() -> None: +def _generate_apidocs_packages(executor: ThreadPoolExecutor) -> None: """Generate API docs for default packages.""" for component_type, default_package in DEFAULT_PACKAGES: public_id = PublicId.from_str(default_package) @@ -156,10 +157,10 @@ def _generate_apidocs_packages() -> None: suffix = Path(str(module_path.relative_to(package_dir))[:-3] + ".md") dotted_path = ".".join(module_path.parts)[:-3] doc_file = API_DIR / type_plural / name / suffix - make_pydoc(dotted_path, doc_file) + executor.submit(make_pydoc, dotted_path, doc_file) -def _generate_apidocs_plugins() -> None: +def _generate_apidocs_plugins(executor: ThreadPoolExecutor) -> None: """Generate API docs for cyrpto plugins.""" for plugin in PLUGIN_DIR.iterdir(): plugin_name = plugin.name @@ -174,7 +175,7 @@ def _generate_apidocs_plugins() -> None: suffix = Path(str(relative_module_path)[:-3] + ".md") dotted_path = ".".join(module_path.parts)[:-3] doc_file = API_DIR / "plugins" / plugin_module_name / suffix - make_pydoc(dotted_path, doc_file) + executor.submit(make_pydoc, dotted_path, doc_file) def make_pydoc(dotted_path: str, dest_file: Path) -> None: @@ -213,9 +214,10 @@ def generate_api_docs() -> None: """Generate the api docs.""" shutil.rmtree(API_DIR, ignore_errors=True) API_DIR.mkdir() - _generate_apidocs_packages() - _generate_apidocs_aea_modules() - _generate_apidocs_plugins() + with ThreadPoolExecutor() as executor: + _generate_apidocs_packages(executor) + _generate_apidocs_aea_modules(executor) + _generate_apidocs_plugins(executor) def install(package: str) -> int: diff --git a/scripts/generate_contract_list.py b/scripts/generate_contract_list.py new file mode 100644 index 0000000000..4c37970407 --- /dev/null +++ b/scripts/generate_contract_list.py @@ -0,0 +1,95 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +# ------------------------------------------------------------------------------ +# +# Copyright 2022-2023 Valory AG +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# ------------------------------------------------------------------------------ + +"""Script to generate a markdown package table.""" + +from pathlib import Path + +import requests + + +DOC_FILE = "docs/advanced_reference/on_chain_addresses.md" +ADDRESS_FILE_URL = "https://raw.githubusercontent.com/valory-xyz/autonolas-registries/main/docs/configuration.json" +CONTRACT_TO_SLUG = { + "ComponentRegistry": "COMPONENT_REGISTRY", + "AgentRegistry": "AGENT_REGISTRY", + "RegistriesManager": "REGISTRIES_MANAGER", + "ServiceRegistry": "SERVICE_REGISTRY", + "ServiceRegistryL2": "SERVICE_REGISTRY", + "ServiceRegistryTokenUtility": "SERVICE_REGISTRY_TOKEN_UTILITY", + "ServiceManagerToken": "SERVICE_MANAGER", + "ServiceManager": "SERVICE_MANAGER", + "GnosisSafeMultisig": "GNOSIS_SAFE_PROXY_FACTORY", + "GnosisSafeSameAddressMultisig": "GNOSIS_SAFE_SAME_ADDRESS_MULTISIG", +} +BLOCKSCAN_URLS = { + "polygon": "https://polygonscan.com/address/", + "polygonMumbai": "https://mumbai.polygonscan.com/address/", + "gnosis": "https://gnosisscan.io/address/", + "chiado": "https://gnosis-chiado.blockscout.com/address/", +} + + +def to_title(string: str) -> str: + """Convert camelCase to snake_case.""" + _string = string[0].upper() + for char in string[1:]: + if char.islower(): + _string += char + else: + _string += " " + _string += char + return _string + + +def main() -> None: + """Generate contract addresses list.""" + data = "# List of contract addresses\n" + chains = requests.get(ADDRESS_FILE_URL).json() + for chain in chains: + chain_name = chain["name"] + chain_id = chain["chainId"] + if chain_id in ("1", "5"): + continue + blockscan_url = BLOCKSCAN_URLS[chain_name] + contracts = chain["contracts"] + table = "| Name | Environment Variable | Address |\n" + table += "| ---- | -------------------- | ------- |\n" + for contract in contracts: + name = contract["name"] + if name not in CONTRACT_TO_SLUG: + continue + spaced_title = to_title(name) + env_var = CONTRACT_TO_SLUG[name] + address = contract["address"] + table += f"| `{spaced_title}` | `CUSTOM_{env_var}_ADDRESS` | [`{address}`]({blockscan_url}{address}) |\n" + + # Multisend address is similar for all chains + table += f"| `Multisend` | `CUSTOM_MULTISEND_ADDRESS` | [`0x40A2aCCbd92BCA938b02010E17A5b8929b49130D`]({blockscan_url}0x40A2aCCbd92BCA938b02010E17A5b8929b49130D) |\n" + section = f"\n## {to_title(chain_name)} ({chain_id})\n" + section += table + data += section + Path(DOC_FILE).write_text(data, encoding="utf-8") + + +# [`0xeB49bE5DF00F74bd240DE4535DDe6Bc89CEfb994`](https://gnosis-chiado.blockscout.com/address/0xeB49bE5DF00F74bd240DE4535DDe6Bc89CEfb994) + +if __name__ == "__main__": + main() diff --git a/scripts/spell-check.sh b/scripts/spell-check.sh deleted file mode 100755 index 1187b179fd..0000000000 --- a/scripts/spell-check.sh +++ /dev/null @@ -1,18 +0,0 @@ -#!/bin/bash -# This script requires `mdspell`: -# -# https://www.npmjs.com/package/markdown-spellcheck -# -# Run this script from the root directory. -# Usage: -# ./scripts/spell-check.sh -# - -MDSPELL_PATH="$(which mdspell)" -if [ -z "${MDSPELL_PATH}" ]; then - echo "Cannot find executable 'mdspell'. Please install it to run this script: npm i markdown-spellcheck -g" - exit 127 -else - echo "Found 'mdspell' executable at ${MDSPELL_PATH}" - mdspell -r -n -a --en-gb '**/*.md' '!docker-images/*.md' '!docs/api/**/*.md' '!third_party/**/*.md' '!go-ipfs/**/*.md' '!docs/package_list.md' -fi diff --git a/scripts/whitelist.py b/scripts/whitelist.py index bcf9f352b7..7d31e84207 100644 --- a/scripts/whitelist.py +++ b/scripts/whitelist.py @@ -217,7 +217,6 @@ _parse_logs # unused function (open-autonomy/autonomy/cli/analyse.py:165) _check_service # unused function (open-autonomy/autonomy/cli/analyse.py:289) get_metavar # unused method (autonomy/cli/utils/click_utils.py:124) -parse_public_id_from_metadata # unused function (autonomy/chain/utils.py:70) -tokenId # unused variable (autonomy/chain/subgraph/client.py:39) -packageHash # unused variable (autonomy/chain/subgraph/client.py:40) -publicId # unused variable (autonomy/chain/subgraph/client.py:41) +_terminate # unused function (autonomy/cli/service.py:162) +_unbond # unused function (autonomy/cli/service.py:186) +_info # unused function (autonomy/cli/service.py:210) diff --git a/setup.cfg b/setup.cfg index a1e0cf7636..e1f272caa5 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,87 +1,4 @@ -[metadata] -name = attr: autonomy.__title__ -author=Valory Ltd. -version = attr: autonomy.__version__ -description = attr: autonomy.__description__ -long_description = file: README.md, CHANGELOG.md, LICENSE -long_description_content_type = "text/markdown" -keywords = aea autonomous-economic-agents agent-framework open-autonomy distributed-systems multi-agent-systems multi-agent cryptocurrency cryptocurrencies dezentralized dezentralized-network -license = Apache 2.0 License -classifiers = - Environment :: Console - Environment :: Web Environment - Development Status :: 2 - Pre-Alpha - Intended Audience :: Developers - License :: OSI Approved :: Apache Software License - Natural Language :: English - Operating System :: MacOS - Operating System :: Unix - Programming Language :: Python :: 3.6 - Programming Language :: Python :: 3.7 - Programming Language :: Python :: 3.8 - Programming Language :: Python :: 3.9 - Topic :: Communications - Topic :: Internet - Topic :: Scientific/Engineering - Topic :: Software Development - Topic :: System - -[option.project_urls] -"Bug Reports": "https://github.com/valory-xyz/open-autonomy/issues" -"Source": "https://github.com/valory-xyz/open-autonomy" - -[options] -zip_safe = False -include_package_data = True -packages = find: -scripts = -install_requires = - open-aea[all]>=1.32.0,<2.0.0 - open-aea-ledger-ethereum>=1.32.0,<2.0.0 - open-aea-ledger-ethereum-hwi>=1.32.0,<2.0.0 - -python_requires= >=3.6 - -[options.package_data] -* = *.txt, *.md - -[options.packages.find] -include = - autonomy* -exclude = - -[bdist_wheel] -# we dont support py2 -universal = 0 - -[flake8] -paths=autonomy,packages,scripts,tests -exclude=.md, - *_pb2.py, - autonomy/__init__.py, - custom_types.py, - *_pb2_grpc.py, - packages/valory/connections/http_client, - packages/valory/connections/ledger, - packages/valory/connections/p2p_libp2p_client, - packages/valory/protocols/acn, - packages/valory/protocols/contract_api, - packages/valory/protocols/http, - packages/valory/protocols/ledger_api -max-line-length = 88 -select = B,C,D,E,F,I,W, -ignore = E203,E501,W503,D202,B014,D400,D401,DAR,B028,B017 -application-import-names = autonomy,packages,tests,scripts - -# ignore as too restrictive for our needs: -# D400: First line should end with a period -# D401: First line should be in imperative mood -# E501: https://www.flake8rules.com/rules/E501.html (Line too long) -# E203: https://www.flake8rules.com/rules/E203.html (Whitespace) -# W503: https://www.flake8rules.com/rules/W503.html (Line break) -# D202: blank lines -# B014: redundant exception - +# keep for generate-all-protocols [isort] # for black compatibility multi_line_output=3 @@ -99,252 +16,4 @@ skip_glob = known_first_party=autonomy known_packages=packages known_local_folder=tests -sections=FUTURE,STDLIB,THIRDPARTY,FIRSTPARTY,PACKAGES,LOCALFOLDER - -[mypy] -python_version = 3.10 -strict_optional = True -exclude=(.*_pb2|.*custom_types|packages/valory/connections/abci/tendermint/abci/|autonomy/data/Dockerfiles|packages/valory/connections/http_client|packages/valory/connections/ledger|packages/valory/connections/p2p_libp2p_client|packages/valory/protocols/acn|packages/valory/protocols/contract_api|packages/valory/protocols/http|packages/valory/protocols/ledger_api|packages/valory/protocols/abci|packages/valory/protocols/tendermint|packages/valory/protocols/ipfs) - -# Before adding a module here, make sure it does not support type hints - -# Per-module options for aea dir: - -[mypy-aea.*] -ignore_missing_imports = True - -[mypy-google.*] -ignore_missing_imports = True - -[mypy-ipfshttpclient.*] -ignore_missing_imports = True - -# Per-module options for examples dir: - -# Per-module options for tests dir: - -[mypy-pytest] -ignore_missing_imports = True - -[mypy-docker.*] -ignore_missing_imports = True - -[mypy-hypothesis.*] -ignore_missing_imports = True - -# Per-module options for packages dir: - -[mypy-eth_keys.*] -ignore_errors=True - -[mypy-eth_account.*] -ignore_missing_imports=True - -[mypy-eth_abi.*] -ignore_missing_imports = True - -[mypy-packages.valory.protocols.abci.custom_types] -ignore_errors=True - -[mypy-packages.valory.protocols.abci.abci_pb2] -ignore_errors=True - -[mypy-packages.valory.protocols.ledger_api.ledger_api_pb2] -ignore_errors=True - -[mypy-packages.valory.protocols.contract_api.contract_api_pb2] -ignore_errors=True - -[mypy-packages.valory.protocols.http.http_pb2] -ignore_errors=True - -[mypy-packages.open_aea.protocols.signing.signing_pb2] -ignore_errors=True - -[mypy-packages.valory.connections.abci.tendermint.types.*] -ignore_errors=True - -[mypy-packages.valory.connections.abci.tendermint.types.types_pb2] -ignore_errors=True - -[mypy-packages.valory.connections.abci.tendermint.abci.types_pb2] -ignore_errors=True - -[mypy-packages.valory.connections.abci.tendermint.abci.types_pb2_grpc] -ignore_errors=True - -[mypy-autonomy.data.Dockerfiles.tendermint.tendermint] -ignore_missing_imports = True - -[mypy-packages.valory.protocols.acn.acn_pb2] -ignore_errors = True - -[mypy-packages.valory.protocols.tendermint.tendermint_pb2] -ignore_errors = True - -[mypy-typed-ast.*] -ignore_missing_imports = True - -[mypy-py_eth_sig_utils.*] -ignore_missing_imports = True - -[mypy-aiohttp.*] -ignore_missing_imports = True - -[mypy-multidict.*] -ignore_missing_imports = True - -[mypy-certifi.*] -ignore_missing_imports = True - -[mypy-eth_typing.*] -ignore_missing_imports = True - -[mypy-packaging.*] -ignore_missing_imports = True - -[mypy-hexbytes.*] -ignore_missing_imports = True - -[mypy-web3.*] -ignore_missing_imports = True - -[mypy-numpy.*] -ignore_missing_imports = True - -[mypy-pandas.*] -ignore_missing_imports = True - -[mypy-_pytest.*] -ignore_missing_imports = True - -[mypy-aea_ledger_ethereum.*] -ignore_missing_imports = True - -[mypy-aea_ledger_ethereum_hwi.*] -ignore_missing_imports = True - -[mypy-google.protobuf.*] -ignore_missing_imports=True - -[mypy-requests.*] -ignore_missing_imports=True - -[mypy-yaml] -ignore_missing_imports=True - -[mypy-jsonschema.*] -ignore_missing_imports=True - -[mypy-pkg_resources] -ignore_missing_imports=True - -# Per-module options for scripts dir: - -[mypy-click.*] -ignore_missing_imports = True - -[mypy-semver.*] -ignore_missing_imports = True - -[mypy-scripts.common.*] -ignore_missing_imports = True - -[mypy-aea_cli_ipfs.*] -ignore_missing_imports = True - -[mypy-watchdog.*] -ignore_missing_imports = True - -[mypy-flask.*] -ignore_missing_imports = True - -[mypy-werkzeug.*] -ignore_missing_imports = True - -[mypy-compose.*] -ignore_missing_imports = True - -[mypy-_strptime.*] -ignore_missing_imports = True - -[mypy-pytz.*] -ignore_missing_imports = True - -[mypy-py_ecc.*] -ignore_missing_imports = True - -[mypy-grpc.*] -ignore_missing_imports = True - -[mypy-pytest_asyncio.*] -ignore_missing_imports = True - -[mypy-gql.*] -ignore_missing_imports = True - -[darglint] -docstring_style=sphinx -strictness=short -ignore_regex=async_act -ignore=DAR401 - - -[MASTER] -ignore-patterns=.*_pb2.py,contract_dispatcher.py,test_abci_messages.py,test_tendermint_messages.py -ignore=packages/valory/protocols/abci,packages/valory/connections/abci/gogoproto - -[MESSAGES CONTROL] -disable=C0103,R0801,C0301,C0201,C0204,C0209,W1203,C0302,R1735,R1729,W0511 - -# See here for more options: https://www.codeac.io/documentation/pylint-configuration.html -R1735: use-dict-literal -R1729: use-a-generator -C0103: invalid-name -C0201: consider-iterating-dictionary -W1203: logging-fstring-interpolation -C0204: bad-mcs-classmethod-argument -C0209: consider-using-f-string -C0301: http://pylint-messages.wikidot.com/messages:c0301 > Line too long -C0302: http://pylint-messages.wikidot.com/messages:c0302 > Too many lines in module -R0801: similar lines - -[IMPORTS] -ignored-modules=pandas,numpy,aea_cli_ipfs,compose,multidict - -[DESIGN] -# min-public-methods=1 -max-public-methods=58 -# max-returns=10 -# max-bool-expr=7 -max-args=6 -# max-locals=31 -# max-statements=80 -max-parents=10 -max-branches=36 -max-attributes=8 - -[REFACTORING] -# max-nested-blocks=6 - -[SPELLING] -# uncomment to enable -# spelling-dict=en_US - -# List of comma separated words that should not be checked. -spelling-ignore-words=nocover,pragma,params,noqa,kwargs,str,async,json,boolean,config,pytest,args,url,tx,jsonschema,traceback,api,nosec - -[SIMILARITIES] - -# Minimum lines number of a similarity. -min-similarity-lines=10 - -# Ignore comments when computing similarities. -ignore-comments=yes - -# Ignore docstrings when computing similarities. -ignore-docstrings=yes - -# Ignore imports when computing similarities. -ignore-imports=no - +sections=FUTURE,STDLIB,THIRDPARTY,FIRSTPARTY,PACKAGES,LOCALFOLDER \ No newline at end of file diff --git a/setup.py b/setup.py index ccd607219b..b5e08db1f5 100644 --- a/setup.py +++ b/setup.py @@ -19,7 +19,6 @@ # ------------------------------------------------------------------------------ import os -import platform import re from typing import Dict @@ -31,11 +30,13 @@ def get_all_extras() -> Dict: - cli_deps = [ "click==8.0.2", - "open-aea-cli-ipfs==1.32.0", - "open-aea-ledger-ethereum-hwi==1.32.0", + "open-aea-cli-ipfs==1.43.0.post2", + "texttable==1.6.7", + "python-dotenv>=0.14.0,<0.18.0", + "pytest>=7.0.0,<7.3.0", + "coverage>=6.4.4,<8.0.0", ] extras = { @@ -52,15 +53,15 @@ def get_all_extras() -> Dict: base_deps = [ "Flask>=2.0.2,<3.0.0", - "open-aea[all]==1.32.0", - "pandas<1.4,>=1.3.4", - "watchdog >=2.1.6", + "open-aea[all]==1.43.0.post2", + "watchdog>=2.1.6", "pytest==7.2.1", - "open-aea-ledger-ethereum==1.32.0", - "docker-compose==1.29.2", + "valory-docker-compose==1.29.3", "werkzeug==2.0.3", - "docker==6.0.0", - "gql==3.4.0" + "docker==6.1.2", + "hexbytes", + "jsonschema<4.4.0,>=4.3.0", + "protobuf<4.25.0,>=4.21.6" ] base_deps.extend(all_extras["cli"]) @@ -124,10 +125,10 @@ def parse_readme(): "Operating System :: MacOS", "Operating System :: Microsoft", "Operating System :: Unix", - "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", "Topic :: Communications", "Topic :: Internet", "Topic :: Scientific/Engineering", @@ -141,7 +142,7 @@ def parse_readme(): zip_safe=False, include_package_data=True, license=about["__license__"], - python_requires=">=3.7", + python_requires=">=3.8", keywords="autonomy open-autonomy aea open-aea autonomous-economic-agents agent-framework multi-agent-systems multi-agent cryptocurrency cryptocurrencies dezentralized dezentralized-network", project_urls={ "Bug Reports": "https://github.com/valory-xyz/open-autonomy/issues", diff --git a/skaffold.yaml b/skaffold.yaml index ad4f720799..51b5f96869 100644 --- a/skaffold.yaml +++ b/skaffold.yaml @@ -1,5 +1,5 @@ .aea_version: &aea_version - AEA_VERSION: "1.32.0" + AEA_VERSION: "1.43.0.post2" AUTHOR: "valory" .docker_args: &docker_args dockerfile: Dockerfile diff --git a/tests/data/dummy_packages/dummy_author/agents/dummy_agent/aea-config.yaml b/tests/data/dummy_packages/dummy_author/agents/dummy_agent/aea-config.yaml index 1129cb5134..f9bdaacbbd 100644 --- a/tests/data/dummy_packages/dummy_author/agents/dummy_agent/aea-config.yaml +++ b/tests/data/dummy_packages/dummy_author/agents/dummy_agent/aea-config.yaml @@ -9,13 +9,13 @@ fingerprint: readme.md: bafybeiacryxttipf4w4frfczygcyxyxhpobbywnybkpbtuuzzsffl2tczy fingerprint_ignore_patterns: [] connections: -- dummy_author/dummy_connection:0.1.0:bafybeiezr7lccxkfv2fslmrngmn6fmjkck6ukah7qfpioobpzuyam2xb2m +- dummy_author/dummy_connection:0.1.0:bafybeic25zmtz5fpbtnr7mycmxqjqhym2uz3jsvfhccbu6lsn3btndx5hq contracts: -- dummy_author/dummy_contract:0.1.0:bafybeigjwno7m7qthgybxwfglwfebnfghadcpmtzsn5kiw7f27ezcb7fyq +- dummy_author/dummy_contract:0.1.0:bafybeifdf4blo6lse4ejlwtqpwzbufg3kh6ttdgde2ilag7ojwauyz6cbm protocols: - dummy_author/dummy_protocol:0.1.0:bafybeifuoztgfa2772jfvx5kyosgz7vrjfu6w6lo2mj3prziomdd3tp5xi skills: -- dummy_author/dummy_skill:0.1.0:bafybeibku44tyjantfk3344gjrwhc2pk3estuose4ewnvf72fjuphe7fjm +- dummy_author/dummy_skill:0.1.0:bafybeiaqnmp4fo336za5q245a2sbd3tqqlglnno2ps6kdzrz6764t4mf5e default_ledger: ethereum required_ledgers: - ethereum diff --git a/tests/data/dummy_packages/dummy_author/connections/dummy_connection/__init__.py b/tests/data/dummy_packages/dummy_author/connections/dummy_connection/__init__.py index 92a420819d..ff6e627ec8 100644 --- a/tests/data/dummy_packages/dummy_author/connections/dummy_connection/__init__.py +++ b/tests/data/dummy_packages/dummy_author/connections/dummy_connection/__init__.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- # ------------------------------------------------------------------------------ # -# Copyright 2023 dummy_author +# Copyright 2023 Valory AG # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/tests/data/dummy_packages/dummy_author/connections/dummy_connection/connection.py b/tests/data/dummy_packages/dummy_author/connections/dummy_connection/connection.py index f2af6cd924..bbb1affc61 100644 --- a/tests/data/dummy_packages/dummy_author/connections/dummy_connection/connection.py +++ b/tests/data/dummy_packages/dummy_author/connections/dummy_connection/connection.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- # ------------------------------------------------------------------------------ # -# Copyright 2023 dummy_author +# Copyright 2023 Valory AG # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/tests/data/dummy_packages/dummy_author/connections/dummy_connection/connection.yaml b/tests/data/dummy_packages/dummy_author/connections/dummy_connection/connection.yaml index 190aa5bb3d..c1354edfa1 100644 --- a/tests/data/dummy_packages/dummy_author/connections/dummy_connection/connection.yaml +++ b/tests/data/dummy_packages/dummy_author/connections/dummy_connection/connection.yaml @@ -7,8 +7,8 @@ description: The scaffold connection provides a scaffold for a connection to be license: Apache-2.0 aea_version: '>=1.0.0, <2.0.0' fingerprint: - __init__.py: bafybeie4rrhvnmbddhuzzkiceshx5jzyhborxdg2csgfpzvdwvtertm434 - connection.py: bafybeiepvdf4agltf4v4ewavsqbzns275paunazakszbnhueangd65sywi + __init__.py: bafybeia3p6wdr7uffr7mke6isfazkez6g52iiwxhqrgcas252m322sbbzm + connection.py: bafybeiggqa6a5yslzwfdb67wux6wg7vjs7pqidq4nxxetz66ecuql5gyei readme.md: bafybeihg5yfzgqvg5ngy7r2o5tfeqnelx2ffxw4po5hmheqjfhumpmxpoq fingerprint_ignore_patterns: [] connections: [] diff --git a/tests/data/dummy_packages/dummy_author/contracts/dummy_contract/__init__.py b/tests/data/dummy_packages/dummy_author/contracts/dummy_contract/__init__.py index d53e6ec0c9..2abcc1e192 100644 --- a/tests/data/dummy_packages/dummy_author/contracts/dummy_contract/__init__.py +++ b/tests/data/dummy_packages/dummy_author/contracts/dummy_contract/__init__.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- # ------------------------------------------------------------------------------ # -# Copyright 2023 dummy_author +# Copyright 2023 Valory AG # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/tests/data/dummy_packages/dummy_author/contracts/dummy_contract/contract.py b/tests/data/dummy_packages/dummy_author/contracts/dummy_contract/contract.py index f59aea38a0..70c98b965b 100644 --- a/tests/data/dummy_packages/dummy_author/contracts/dummy_contract/contract.py +++ b/tests/data/dummy_packages/dummy_author/contracts/dummy_contract/contract.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- # ------------------------------------------------------------------------------ # -# Copyright 2023 dummy_author +# Copyright 2023 Valory AG # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -27,7 +27,7 @@ from aea.crypto.base import LedgerApi -class MyScaffoldContract(Contract): +class ERC20TokenContract(Contract): """The scaffold contract class for a smart contract.""" contract_id = PublicId.from_str("open_aea/scaffold:0.1.0") diff --git a/tests/data/dummy_packages/dummy_author/contracts/dummy_contract/contract.yaml b/tests/data/dummy_packages/dummy_author/contracts/dummy_contract/contract.yaml index 66ec0ecbc4..e47fbe62b7 100644 --- a/tests/data/dummy_packages/dummy_author/contracts/dummy_contract/contract.yaml +++ b/tests/data/dummy_packages/dummy_author/contracts/dummy_contract/contract.yaml @@ -6,10 +6,10 @@ description: The scaffold contract scaffolds a contract to be implemented by the license: Apache-2.0 aea_version: '>=1.0.0, <2.0.0' fingerprint: - __init__.py: bafybeibdtu3vxwxt4mialjngrsdkupiog2ec2q55ur5gd6sr4ycmpsjpou - contract.py: bafybeiao6o6secn46xfha2d5vafknbeiej2xjopeptbajqn77hcsow7xte + __init__.py: bafybeicqln5tyudb5bzg27wale3xjvuliat6ipn6hntg5pqtnllex4pyre + contract.py: bafybeihwzoluzg62l3i64ccxaxs2dep766crx3lviuc3typfpmbrjgfg3a fingerprint_ignore_patterns: [] -class_name: MyScaffoldContract +class_name: ERC20TokenContract contract_interface_paths: {} dependencies: {} contracts: [] diff --git a/tests/data/dummy_packages/dummy_author/services/dummy_service/service.yaml b/tests/data/dummy_packages/dummy_author/services/dummy_service/service.yaml index a394147c78..d2279fe29e 100644 --- a/tests/data/dummy_packages/dummy_author/services/dummy_service/service.yaml +++ b/tests/data/dummy_packages/dummy_author/services/dummy_service/service.yaml @@ -8,5 +8,6 @@ fingerprint: README.md: bafybeidtsspnbrkqb55jjnpl3ai5qhcoumm6h5dqf76e6gxldklbxmdusi fingerprint_ignore_patterns: [] number_of_agents: 1 -agent: dummy_author/dummy_agent:0.1.0:bafybeihjl5fgwnfecwknnhulebj3e7ktyz6ba6flbjwmpibzj2ih3gweo4 -deployment: {} \ No newline at end of file +agent: dummy_author/dummy_agent:0.1.0:bafybeigqqikxfon7lddqux2qocdf2vlpq2zrjhmtpve5j3z5lijeapodsu +deployment: {} +dependencies: {} diff --git a/tests/data/dummy_packages/dummy_author/skills/dummy_skill/__init__.py b/tests/data/dummy_packages/dummy_author/skills/dummy_skill/__init__.py index 99b2b259f6..bf700dfada 100644 --- a/tests/data/dummy_packages/dummy_author/skills/dummy_skill/__init__.py +++ b/tests/data/dummy_packages/dummy_author/skills/dummy_skill/__init__.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- # ------------------------------------------------------------------------------ # -# Copyright 2023 dummy_author +# Copyright 2023 Valory AG # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/tests/data/dummy_packages/dummy_author/skills/dummy_skill/behaviours.py b/tests/data/dummy_packages/dummy_author/skills/dummy_skill/behaviours.py index c519424bb2..c16965a3b0 100644 --- a/tests/data/dummy_packages/dummy_author/skills/dummy_skill/behaviours.py +++ b/tests/data/dummy_packages/dummy_author/skills/dummy_skill/behaviours.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- # ------------------------------------------------------------------------------ # -# Copyright 2023 dummy_author +# Copyright 2023 Valory AG # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/tests/data/dummy_packages/dummy_author/skills/dummy_skill/handlers.py b/tests/data/dummy_packages/dummy_author/skills/dummy_skill/handlers.py index 586924c6bf..479b6c0fb6 100644 --- a/tests/data/dummy_packages/dummy_author/skills/dummy_skill/handlers.py +++ b/tests/data/dummy_packages/dummy_author/skills/dummy_skill/handlers.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- # ------------------------------------------------------------------------------ # -# Copyright 2023 dummy_author +# Copyright 2023 Valory AG # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/tests/data/dummy_packages/dummy_author/skills/dummy_skill/my_model.py b/tests/data/dummy_packages/dummy_author/skills/dummy_skill/my_model.py index 74ea49ed9d..d1cbbf98c2 100644 --- a/tests/data/dummy_packages/dummy_author/skills/dummy_skill/my_model.py +++ b/tests/data/dummy_packages/dummy_author/skills/dummy_skill/my_model.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- # ------------------------------------------------------------------------------ # -# Copyright 2023 dummy_author +# Copyright 2023 Valory AG # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/tests/data/dummy_packages/dummy_author/skills/dummy_skill/skill.yaml b/tests/data/dummy_packages/dummy_author/skills/dummy_skill/skill.yaml index f95bc217ef..8c99c8492f 100644 --- a/tests/data/dummy_packages/dummy_author/skills/dummy_skill/skill.yaml +++ b/tests/data/dummy_packages/dummy_author/skills/dummy_skill/skill.yaml @@ -6,15 +6,15 @@ description: The scaffold skill is a scaffold for your own skill implementation. license: Apache-2.0 aea_version: '>=1.0.0, <2.0.0' fingerprint: - __init__.py: bafybeigcrc4d2l5dtshvkz7rsokqmhb7ku2274my6zgvknwvszwoxg67ly - behaviours.py: bafybeiaebqkzpxtcxfq7ubw6ggghuzigrmg7gbohttd6xicvejl5dymmsq - handlers.py: bafybeicobt2sakex5iu47q67nedk74ccszhkeo2gfugkikzhnssqgxvmtq - my_model.py: bafybeic3ptxpsvhkemmqj2h7omqxarfdyhpvtyogpwvrorswxpgedcduxm + __init__.py: bafybeican67qhwviyzntp6kn6yzzqdpppe7sukjxyghhhkw6hd2irpwp3m + behaviours.py: bafybeib6llpmzo74qmzsp2mgtk3hlhykopxejzo4ukumgl7xzyjdgsqeze + handlers.py: bafybeiby737xlo5f7np43oir6koyimarbonpvilfbjvy4e3nghbiao6gau + my_model.py: bafybeih2gccbbqlf6f45akn43rvp5qnupvudqxz37wcnvhtvk3rqnppeky fingerprint_ignore_patterns: [] connections: -- dummy_author/dummy_connection:0.1.0:bafybeiezr7lccxkfv2fslmrngmn6fmjkck6ukah7qfpioobpzuyam2xb2m +- dummy_author/dummy_connection:0.1.0:bafybeic25zmtz5fpbtnr7mycmxqjqhym2uz3jsvfhccbu6lsn3btndx5hq contracts: -- dummy_author/dummy_contract:0.1.0:bafybeigjwno7m7qthgybxwfglwfebnfghadcpmtzsn5kiw7f27ezcb7fyq +- dummy_author/dummy_contract:0.1.0:bafybeifdf4blo6lse4ejlwtqpwzbufg3kh6ttdgde2ilag7ojwauyz6cbm protocols: - dummy_author/dummy_protocol:0.1.0:bafybeifuoztgfa2772jfvx5kyosgz7vrjfu6w6lo2mj3prziomdd3tp5xi skills: [] diff --git a/tests/data/dummy_packages/packages.json b/tests/data/dummy_packages/packages.json index 85d7225570..e118e2023f 100644 --- a/tests/data/dummy_packages/packages.json +++ b/tests/data/dummy_packages/packages.json @@ -1,11 +1,11 @@ { "dev": { "protocol/dummy_author/dummy_protocol/0.1.0": "bafybeifuoztgfa2772jfvx5kyosgz7vrjfu6w6lo2mj3prziomdd3tp5xi", - "contract/dummy_author/dummy_contract/0.1.0": "bafybeigjwno7m7qthgybxwfglwfebnfghadcpmtzsn5kiw7f27ezcb7fyq", - "connection/dummy_author/dummy_connection/0.1.0": "bafybeiezr7lccxkfv2fslmrngmn6fmjkck6ukah7qfpioobpzuyam2xb2m", - "skill/dummy_author/dummy_skill/0.1.0": "bafybeibku44tyjantfk3344gjrwhc2pk3estuose4ewnvf72fjuphe7fjm", - "agent/dummy_author/dummy_agent/0.1.0": "bafybeihjl5fgwnfecwknnhulebj3e7ktyz6ba6flbjwmpibzj2ih3gweo4", - "service/dummy_author/dummy_service/0.1.0": "bafybeiehaezsrmyhndukl4cts75nlx2rtkoomwn26vqxbtsa4crzwj3lje" + "contract/dummy_author/dummy_contract/0.1.0": "bafybeifdf4blo6lse4ejlwtqpwzbufg3kh6ttdgde2ilag7ojwauyz6cbm", + "connection/dummy_author/dummy_connection/0.1.0": "bafybeic25zmtz5fpbtnr7mycmxqjqhym2uz3jsvfhccbu6lsn3btndx5hq", + "skill/dummy_author/dummy_skill/0.1.0": "bafybeiaqnmp4fo336za5q245a2sbd3tqqlglnno2ps6kdzrz6764t4mf5e", + "agent/dummy_author/dummy_agent/0.1.0": "bafybeigqqikxfon7lddqux2qocdf2vlpq2zrjhmtpve5j3z5lijeapodsu", + "service/dummy_author/dummy_service/0.1.0": "bafybeibw4gtticok3fbis2fndtz2flxwycylk4wd4n7c5tshjfp6vlrfxi" }, "third_party": {} } \ No newline at end of file diff --git a/tests/data/dummy_service_config_files/service_0.yaml b/tests/data/dummy_service_config_files/service_0.yaml index a962bb1a7e..bcd55c220a 100644 --- a/tests/data/dummy_service_config_files/service_0.yaml +++ b/tests/data/dummy_service_config_files/service_0.yaml @@ -9,4 +9,5 @@ fingerprint: fingerprint_ignore_patterns: [] agent: valory/hello_world:0.1.0:bafybeiaotnukv7oq2sknot73a4zssrrnjezh6nd2fwptrznxtnovy2rusm number_of_agents: 1 -deployment: {} \ No newline at end of file +deployment: {} +dependencies: {} diff --git a/tests/data/dummy_service_config_files/service_1.yaml b/tests/data/dummy_service_config_files/service_1.yaml index a35fa175b7..73946a51da 100644 --- a/tests/data/dummy_service_config_files/service_1.yaml +++ b/tests/data/dummy_service_config_files/service_1.yaml @@ -10,6 +10,7 @@ fingerprint_ignore_patterns: [] agent: valory/hello_world:0.1.0:bafybeiaotnukv7oq2sknot73a4zssrrnjezh6nd2fwptrznxtnovy2rusm number_of_agents: 1 deployment: {} +dependencies: {} --- public_id: valory/dummy_skill:0.1.0 type: skill diff --git a/tests/data/dummy_service_config_files/service_2.yaml b/tests/data/dummy_service_config_files/service_2.yaml index a1ca517dbb..f9c1030f2b 100644 --- a/tests/data/dummy_service_config_files/service_2.yaml +++ b/tests/data/dummy_service_config_files/service_2.yaml @@ -10,6 +10,7 @@ fingerprint_ignore_patterns: [] agent: valory/hello_world:0.1.0:bafybeiaotnukv7oq2sknot73a4zssrrnjezh6nd2fwptrznxtnovy2rusm number_of_agents: 4 deployment: {} +dependencies: {} --- extra: benchmark_persistence_params: diff --git a/tests/data/dummy_service_config_files/service_3.yaml b/tests/data/dummy_service_config_files/service_3.yaml index 02f626e494..68cf7a9801 100644 --- a/tests/data/dummy_service_config_files/service_3.yaml +++ b/tests/data/dummy_service_config_files/service_3.yaml @@ -10,6 +10,7 @@ fingerprint_ignore_patterns: [] agent: valory/hello_world:0.1.0:bafybeiaotnukv7oq2sknot73a4zssrrnjezh6nd2fwptrznxtnovy2rusm number_of_agents: 4 deployment: {} +dependencies: {} --- public_id: valory/dummy_connection:0.1.0 type: connection diff --git a/tests/data/dummy_service_config_files/service_4.yaml b/tests/data/dummy_service_config_files/service_4.yaml index d7643c3bfd..82876e4629 100644 --- a/tests/data/dummy_service_config_files/service_4.yaml +++ b/tests/data/dummy_service_config_files/service_4.yaml @@ -10,6 +10,7 @@ fingerprint_ignore_patterns: [] agent: valory/hello_world:0.1.0:bafybeiaotnukv7oq2sknot73a4zssrrnjezh6nd2fwptrznxtnovy2rusm number_of_agents: 4 deployment: {} +dependencies: {} --- extra: benchmark_persistence_params: diff --git a/tests/test_autonomy/test_analyse/test_logs.py b/tests/test_autonomy/test_analyse/test_logs.py new file mode 100644 index 0000000000..29372bcc19 --- /dev/null +++ b/tests/test_autonomy/test_analyse/test_logs.py @@ -0,0 +1,72 @@ +# -*- coding: utf-8 -*- +# ------------------------------------------------------------------------------ +# +# Copyright 2023 Valory AG +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# ------------------------------------------------------------------------------ + +"""Test log parser.""" + +import tempfile +from pathlib import Path + +from autonomy.analyse.logs.collection import LogCollection + + +LOGS = """[2023-09-26 06:27:56,015] [INFO] [agent] Entered in the 'check_transaction_history_behaviour' behaviour +[2023-09-26 06:27:56,078] [ERROR] [agent] get_safe_nonce unsuccessful! Received: Message(sender=valory/ledger:0.19.0,to=valory/trader_abci:0.1.0,code=500,data=b'',dialogue_reference=('974278ff7b4e00019f7542a193987a8359b1c785d11a98a84bfaff2ea77b1e8f', '6b8e33fe183de2ac45e8d8f9625db5562b6230677fdc6995efc4ce05c798f83a'),message=Traceback (most recent call last): + + File "/usr/lib/python3.10/http/client.py", line 287, in _read_status + raise RemoteDisconnected("Remote end closed connection without" + +http.client.RemoteDisconnected: Remote end closed connection without response + + +During handling of the above exception, another exception occurred: + + +Traceback (most recent call last): + + File "/usr/lib/python3.10/http/client.py", line 287, in _read_status + raise RemoteDisconnected("Remote end closed connection without" + +urllib3.exceptions.ProtocolError: ('Connection aborted.', RemoteDisconnected('Remote end closed co,message_id=-1,performative=error,target=1) +[2023-09-26 06:27:56,103] [INFO] [agent] arrived block with timestamp: 2023-09-26 06:27:55.040545 +""" + +LOGS_CLEAN = """Entered in the 'check_transaction_history_behaviour' behaviour +get_safe_nonce unsuccessful! Received: Message(sender=valory/ledger:0.19.0,to=valory/trader_abci:0.1.0,code=500,data=b'',dialogue_reference=('974278ff7b4e00019f7542a193987a8359b1c785d11a98a84bfaff2ea77b1e8f', '6b8e33fe183de2ac45e8d8f9625db5562b6230677fdc6995efc4ce05c798f83a'),message=Traceback (most recent call last): +File "/usr/lib/python3.10/http/client.py", line 287, in _read_status +raise RemoteDisconnected("Remote end closed connection without" +http.client.RemoteDisconnected: Remote end closed connection without response +During handling of the above exception, another exception occurred: +Traceback (most recent call last): +File "/usr/lib/python3.10/http/client.py", line 287, in _read_status +raise RemoteDisconnected("Remote end closed connection without" +urllib3.exceptions.ProtocolError: ('Connection aborted.', RemoteDisconnected('Remote end closed co,message_id=-1,performative=error,target=1) +arrived block with timestamp: 2023-09-26 06:27:55.040545 +""" + + +def test_multiline_parse() -> None: + """Test multiline logs parsing.""" + + with tempfile.TemporaryDirectory() as temp_dir: + file = Path(temp_dir, "log.txt") + file.write_text(LOGS) + parsed = "\n".join(list(map(lambda x: x[2], LogCollection.parse(file=file)))) + + for line in LOGS_CLEAN.split("\n"): + assert line in parsed diff --git a/tests/test_autonomy/test_chain/base.py b/tests/test_autonomy/test_chain/base.py index 9c4c3db0e0..8d80238726 100644 --- a/tests/test_autonomy/test_chain/base.py +++ b/tests/test_autonomy/test_chain/base.py @@ -34,20 +34,12 @@ from autonomy.chain.base import registry_contracts from autonomy.chain.config import ChainType -from autonomy.chain.constants import ( - AGENT_REGISTRY_ADDRESS_LOCAL, - COMPONENT_REGISTRY_ADDRESS_LOCAL, - SERVICE_REGISTRY_ADDRESS_LOCAL, -) +from autonomy.chain.constants import HardhatAddresses from autonomy.chain.metadata import publish_metadata -from autonomy.chain.mint import ( - DEFAULT_NFT_IMAGE_HASH, - UnitType, - mint_component, - mint_service, -) +from autonomy.chain.mint import DEFAULT_NFT_IMAGE_HASH, MintManager, UnitType +from autonomy.chain.service import ServiceManager from autonomy.chain.utils import parse_public_id_from_metadata, resolve_component_id -from autonomy.cli.helpers.chain import get_ledger_and_crypto_objects +from autonomy.cli.helpers.chain import OnChainHelper from autonomy.cli.packages import get_package_manager from tests.conftest import DATA_DIR @@ -108,6 +100,8 @@ class BaseChainInteractionTest(BaseCliTest): ledger_api: LedgerApi crypto: Crypto chain_type: ChainType = ChainType.LOCAL + mint_manager: MintManager + service_manager: ServiceManager key_file: Path = ETHEREUM_KEY_DEPLOYER @@ -121,10 +115,20 @@ def setup_class(cls) -> None: """Setup class.""" super().setup_class() - cls.ledger_api, cls.crypto = get_ledger_and_crypto_objects( + cls.ledger_api, cls.crypto = OnChainHelper.get_ledger_and_crypto_objects( chain_type=cls.chain_type, key=cls.key_file, ) + cls.mint_manager = MintManager( + ledger_api=cls.ledger_api, + crypto=cls.crypto, + chain_type=cls.chain_type, + ) + cls.service_manager = ServiceManager( + ledger_api=cls.ledger_api, + crypto=cls.crypto, + chain_type=cls.chain_type, + ) @staticmethod def extract_token_id_from_output(output: str) -> int: @@ -145,7 +149,7 @@ def verify_owner_address( on_chain_owner = ( registry_contracts.service_registry.get_instance( ledger_api=self.ledger_api, - contract_address=SERVICE_REGISTRY_ADDRESS_LOCAL, + contract_address=HardhatAddresses.service_registry, ) .functions.ownerOf(token_id) .call() @@ -154,7 +158,7 @@ def verify_owner_address( on_chain_owner = ( registry_contracts.component_registry.get_instance( ledger_api=self.ledger_api, - contract_address=AGENT_REGISTRY_ADDRESS_LOCAL, + contract_address=HardhatAddresses.agent_registry, ) .functions.ownerOf(token_id) .call() @@ -163,7 +167,7 @@ def verify_owner_address( on_chain_owner = ( registry_contracts.component_registry.get_instance( ledger_api=self.ledger_api, - contract_address=COMPONENT_REGISTRY_ADDRESS_LOCAL, + contract_address=HardhatAddresses.component_registry, ) .functions.ownerOf(token_id) .call() @@ -180,11 +184,11 @@ def verify_minted_token_id(self, token_id: int, package_id: PackageId) -> None: is_service = package_id.package_type == PackageType.SERVICE if is_service: - contract_address = SERVICE_REGISTRY_ADDRESS_LOCAL + contract_address = HardhatAddresses.service_registry elif is_agent: - contract_address = AGENT_REGISTRY_ADDRESS_LOCAL + contract_address = HardhatAddresses.agent_registry else: - contract_address = COMPONENT_REGISTRY_ADDRESS_LOCAL + contract_address = HardhatAddresses.component_registry metadata = resolve_component_id( ledger_api=self.ledger_api, @@ -229,19 +233,13 @@ def mint_component( assert ( service_mint_parameters is not None ), "Please provide service mint parameters" - token_id = mint_service( - ledger_api=self.ledger_api, - crypto=self.crypto, + token_id = self.mint_manager.mint_service( metadata_hash=metadata_hash, - chain_type=ChainType.LOCAL, **service_mint_parameters, ) else: - token_id = mint_component( - ledger_api=self.ledger_api, - crypto=self.crypto, + token_id = self.mint_manager.mint_component( metadata_hash=metadata_hash, - chain_type=ChainType.LOCAL, component_type=( UnitType.AGENT if package_id.package_type == PackageType.AGENT diff --git a/tests/test_autonomy/test_chain/test_addresses.py b/tests/test_autonomy/test_chain/test_addresses.py new file mode 100644 index 0000000000..871b18d6de --- /dev/null +++ b/tests/test_autonomy/test_chain/test_addresses.py @@ -0,0 +1,82 @@ +# -*- coding: utf-8 -*- +# ------------------------------------------------------------------------------ +# +# Copyright 2023 Valory AG +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# ------------------------------------------------------------------------------ + +"""Verify the on-chain addresses against the defined constants.""" + +import typing as t + +import pytest +import requests + +from autonomy.chain.config import ChainType +from autonomy.chain.constants import ( + ContractAddresses, + EthereumAddresses, + GoerliAddresses, +) + + +ADDRESS_FILE_URL = "https://raw.githubusercontent.com/valory-xyz/autonolas-registries/main/docs/configuration.json" +CHAIN_SLUGS = {ChainType.ETHEREUM: "mainnet", ChainType.GOERLI: "goerli"} +ADDRESSES_TO_CHECK = { + "ComponentRegistry": "component_registry", + "AgentRegistry": "agent_registry", + "RegistriesManager": "registries_manager", + "ServiceRegistry": "service_registry", + "ServiceRegistryTokenUtility": "service_registry_token_utility", + "ServiceManagerToken": "service_manager", + "GnosisSafeMultisig": "gnosis_safe_proxy_factory", + "GnosisSafeSameAddressMultisig": "gnosis_safe_same_address_multisig", # noqa: E800 +} + + +class TestAddresses: + """Test addesses.""" + + contracts: t.Dict[str, t.List[t.Dict[str, str]]] + + @classmethod + def setup_class(cls) -> None: + """Setup test class.""" + chain_configs = requests.get(url=ADDRESS_FILE_URL).json() + cls.contracts = { + config["name"]: config["contracts"] for config in chain_configs + } + + @pytest.mark.parametrize( + argnames="chain,addresses", + argvalues=( + (ChainType.ETHEREUM, EthereumAddresses), + (ChainType.GOERLI, GoerliAddresses), + ), + ) + def test_addresses_match( + self, chain: ChainType, addresses: ContractAddresses + ) -> None: + """Test addresses match with the remote file.""" + contracts = self.contracts[CHAIN_SLUGS[chain]] + for contract in contracts: + name = contract["name"] + if name not in ADDRESSES_TO_CHECK: + continue + address = contract["address"] + constant_address = addresses.get(name=ADDRESSES_TO_CHECK[name]) + assert ( + address == constant_address + ), f"Constant value and remote value does not match for `{name}`" diff --git a/tests/test_autonomy/test_chain/test_mint.py b/tests/test_autonomy/test_chain/test_mint.py index 3855f6a8e6..aea9478bea 100644 --- a/tests/test_autonomy/test_chain/test_mint.py +++ b/tests/test_autonomy/test_chain/test_mint.py @@ -30,7 +30,7 @@ from autonomy.chain.config import ChainType from autonomy.chain.constants import COMPONENT_REGISTRY_CONTRACT, CONTRACTS_DIR_LOCAL from autonomy.chain.exceptions import InvalidMintParameter -from autonomy.chain.mint import mint_service, sort_service_dependency_metadata +from autonomy.chain.mint import MintManager, sort_service_dependency_metadata, transact from tests.test_autonomy.test_chain.base import DUMMY_HASH @@ -40,7 +40,6 @@ argvalues=( ( dict( - chain_type=ChainType.LOCAL, metadata_hash=DUMMY_HASH, agent_ids=[], number_of_slots_per_agent=[], @@ -51,7 +50,6 @@ ), ( dict( - chain_type=ChainType.LOCAL, metadata_hash=DUMMY_HASH, agent_ids=[1], number_of_slots_per_agent=[], @@ -62,7 +60,6 @@ ), ( dict( - chain_type=ChainType.LOCAL, metadata_hash=DUMMY_HASH, agent_ids=[1], number_of_slots_per_agent=[4], @@ -73,7 +70,6 @@ ), ( dict( - chain_type=ChainType.LOCAL, metadata_hash=DUMMY_HASH, agent_ids=[1], number_of_slots_per_agent=[4], @@ -87,7 +83,6 @@ ), ( dict( - chain_type=ChainType.LOCAL, metadata_hash=DUMMY_HASH, agent_ids=[1], number_of_slots_per_agent=[0], @@ -98,7 +93,6 @@ ), ( dict( - chain_type=ChainType.LOCAL, metadata_hash=DUMMY_HASH, agent_ids=[1], number_of_slots_per_agent=[4], @@ -113,11 +107,11 @@ def test_mint_service_invalid_paramters(parameters: Dict, error_message: str) -> """Test invalid parameters""" with pytest.raises(InvalidMintParameter, match=error_message): - mint_service( + MintManager( ledger_api=mock.MagicMock(), # type: ignore crypto=mock.MagicMock(), # type: ignore - **parameters - ) + chain_type=ChainType.LOCAL, + ).mint_service(**parameters) def test_get_contract_method() -> None: @@ -137,7 +131,9 @@ def test_get_contract_method() -> None: "please reinstall the package" ), ): - contract = registry_contracts.get_contract(COMPONENT_REGISTRY_CONTRACT) + contract = registry_contracts.get_contract( + COMPONENT_REGISTRY_CONTRACT, cache=False + ) def test_sort_service_dependency_metadata() -> None: @@ -165,3 +161,15 @@ def test_sort_service_dependency_metadata() -> None: assert cal_agent_ids == expected_agent_ids assert cal_number_of_slots_per_agents == expected_number_of_slots_per_agents assert cal_cost_of_bond_per_agent == expected_cost_of_bond_per_agent + + +def test_transaction_timeout() -> None: + """Test transaction timeout.""" + with pytest.raises(TimeoutError): + transact( + ledger_api=mock.MagicMock(), + crypto=mock.MagicMock(), + tx={}, + sleep=1.0, + timeout=-1.0, + ) diff --git a/tests/test_autonomy/test_chain/test_service.py b/tests/test_autonomy/test_chain/test_service.py new file mode 100644 index 0000000000..6a75489fa0 --- /dev/null +++ b/tests/test_autonomy/test_chain/test_service.py @@ -0,0 +1,73 @@ +# -*- coding: utf-8 -*- +# ------------------------------------------------------------------------------ +# +# Copyright 2023 Valory AG +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# ------------------------------------------------------------------------------ + +"""Test service helpers.""" + + +from aea_test_autonomy.fixture_helpers import registries_scope_class # noqa: F401 + +from autonomy.chain.service import get_reuse_multisig_payload + +from tests.test_autonomy.test_chain.base import ( + AGENT_ID, + BaseChainInteractionTest, + COST_OF_BOND_FOR_AGENT, + DUMMY_SERVICE, + NUMBER_OF_SLOTS_PER_AGENT, + THRESHOLD, +) + + +class TestReuseMultisigPayload(BaseChainInteractionTest): + """Test get_reuse_multisig_payload method.""" + + def test_inproper_termination(self) -> None: + """Test inproper termination failure""" + + _, error = get_reuse_multisig_payload( + ledger_api=self.ledger_api, + crypto=self.crypto, + chain_type=self.chain_type, + service_id=1, + ) + + assert ( + error + == "Service was not terminated properly, the service owner should be the only owner of the safe" + ) + + def test_no_previous_deployment(self) -> None: + """Test inproper termination failure""" + service_id = self.mint_component( + package_id=DUMMY_SERVICE, + service_mint_parameters=dict( + agent_ids=[AGENT_ID], + number_of_slots_per_agent=[NUMBER_OF_SLOTS_PER_AGENT], + cost_of_bond_per_agent=[COST_OF_BOND_FOR_AGENT], + threshold=THRESHOLD, + ), + ) + _, error = get_reuse_multisig_payload( + ledger_api=self.ledger_api, + crypto=self.crypto, + chain_type=self.chain_type, + service_id=service_id, + ) + + assert error == "Cannot reuse multisig, No previous deployment exist!" diff --git a/tests/test_autonomy/test_chain/test_tx.py b/tests/test_autonomy/test_chain/test_tx.py new file mode 100644 index 0000000000..d234e0e591 --- /dev/null +++ b/tests/test_autonomy/test_chain/test_tx.py @@ -0,0 +1,204 @@ +# -*- coding: utf-8 -*- +# ------------------------------------------------------------------------------ +# +# Copyright 2023 Valory AG +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# ------------------------------------------------------------------------------ + +"""Test tx settlement tool.""" + +from typing import Any +from unittest import mock + +import pytest +from requests.exceptions import ConnectionError as RequestsConnectionError + +from autonomy.chain.config import ChainType +from autonomy.chain.exceptions import ChainInteractionError, ChainTimeoutError, RPCError +from autonomy.chain.tx import TxSettler + + +def test_rpc_error() -> None: + """Test RPC error.""" + settler = TxSettler( + ledger_api=mock.Mock(), + crypto=mock.Mock(), + chain_type=ChainType.LOCAL, + ) + + def _waitable(*args: Any, **kwargs: Any) -> Any: + raise RequestsConnectionError() + + with pytest.raises(RPCError): + settler.transact(_waitable, "service_registry", {}) + + +def test_none_retriable_exception() -> None: + """Test none retriable exception.""" + settler = TxSettler( + ledger_api=mock.Mock(), + crypto=mock.Mock(), + chain_type=ChainType.LOCAL, + ) + + def _method(*args: Any, **kwargs: Any) -> Any: + raise Exception("some error") + + with pytest.raises(ChainInteractionError): + settler.transact(_method, contract="service_registry", kwargs={}) # type: ignore + + +def test_retriable_exception(capsys: Any) -> None: + """Test retriable exception.""" + + class _retriable_method: + should_raise = True + + def __call__(self, *args: Any, **kwargs: Any) -> Any: + if self.should_raise: + self.should_raise = False + raise Exception("wrong transaction nonce") + return {} + + settler = TxSettler( + ledger_api=mock.Mock(), + crypto=mock.Mock(), + chain_type=ChainType.LOCAL, + ) + settler.transact(_retriable_method(), contract="service_registry", kwargs={}) # type: ignore + captured = capsys.readouterr() + assert "Error occured when interacting with chain" in captured.out + + +def test_repricing(capsys: Any) -> None: + """Test retriable exception.""" + + class _repricable_method: + tx_dict = { + "maxFeePerGas": 100, + "maxPriorityFeePerGas": 100, + } + + def __call__(self, *args: Any, **kwargs: Any) -> Any: + return self.tx_dict + + def _raise_fee_too_low(tx_signed: Any, **kwargs: Any) -> None: + if tx_signed["maxFeePerGas"] == 110: + return + raise Exception("FeeTooLow") + + def _reprice(old_price: Any, **kwargs: Any) -> Any: + return {"maxFeePerGas": 110, "maxPriorityFeePerGas": 110} + + settler = TxSettler( + ledger_api=mock.Mock( + send_signed_transaction=_raise_fee_too_low, + try_get_gas_pricing=_reprice, + ), + crypto=mock.Mock( + sign_transaction=lambda transaction: transaction, + ), + chain_type=ChainType.LOCAL, + ) + settler.transact(_repricable_method(), contract="service_registry", kwargs={}) # type: ignore + captured = capsys.readouterr() + assert "Repricing the transaction..." in captured.out + + +def test_tx_not_found(capsys: Any) -> None: + """Test retriable exception.""" + + class _get_transaction_receipt: + _should_raise = True + + def __call__(self, *args: Any, **kwargs: Any) -> Any: + if self._should_raise: + self._should_raise = False + raise Exception("Transaction with hash HASH not found") + return "receipt" + + settler = TxSettler( + ledger_api=mock.Mock( + api=mock.Mock( + eth=mock.Mock( + get_transaction_receipt=_get_transaction_receipt(), + ) + ) + ), + crypto=mock.Mock( + sign_transaction=lambda transaction: transaction, + ), + chain_type=ChainType.LOCAL, + ) + settler.transact(mock.Mock(), contract="service_registry", kwargs={}) # type: ignore + captured = capsys.readouterr() + + assert "Error occured when interacting with chain" in captured.out + assert "Transaction with hash HASH not found" in captured.out + assert "will retry in 3.0..." in captured.out + + +def test_already_known(capsys: Any) -> None: + """Test AlreadyKnown exception.""" + + class _method: + def __call__(self, *args: Any, **kwargs: Any) -> Any: + return {} + + class _raise: + _should_raise = True + + def __call__(self, *args: Any, **kwargs: Any) -> Any: + if self._should_raise: + self._should_raise = False + raise Exception("AlreadyKnown") + return {} + + settler = TxSettler( + ledger_api=mock.Mock( + send_signed_transaction=_raise(), + ), + crypto=mock.Mock( + sign_transaction=lambda transaction: transaction, + ), + chain_type=ChainType.LOCAL, + ) + with mock.patch.object(settler, "_already_known") as _mock: + settler.transact(_method(), contract="service_registry", kwargs={}) # type: ignore + _mock.assert_called_with("AlreadyKnown") + + +def test_timeout() -> None: + """Test transact.""" + + def _waitable(*arg: Any, **kwargs: Any) -> None: + return None + + settler = TxSettler( + ledger_api=mock.Mock( + api=mock.Mock( + eth=mock.Mock( + get_transaction_receipt=_waitable, + ) + ) + ), + crypto=mock.Mock(), + chain_type=ChainType.LOCAL, + sleep=0.1, + retries=1, + ) + + with pytest.raises(ChainTimeoutError): + settler.transact(lambda **x: None, "service_registry", {}) # type: ignore diff --git a/tests/test_autonomy/test_chain/test_utils.py b/tests/test_autonomy/test_chain/test_utils.py index 845479f3e2..955ee788b7 100644 --- a/tests/test_autonomy/test_chain/test_utils.py +++ b/tests/test_autonomy/test_chain/test_utils.py @@ -19,16 +19,22 @@ """Test utils.""" +import re from typing import Dict from unittest import mock import pytest -from aea.configurations.data_types import PublicId -from aea.contracts.base import Contract -from requests.exceptions import ConnectionError as RequestConnectionError +from aea.configurations.data_types import PackageId, PublicId -from autonomy.chain.exceptions import DependencyError, FailedToRetrieveComponentMetadata -from autonomy.chain.utils import parse_public_id_from_metadata, resolve_component_id +from autonomy.chain.exceptions import DependencyError +from autonomy.chain.utils import ( + get_ipfs_hash_from_uri, + parse_public_id_from_metadata, + verify_component_dependencies, + verify_service_dependencies, +) + +from tests.test_autonomy.test_chain.base import DUMMY_HASH def get_dummy_metadata( @@ -49,10 +55,218 @@ def get_dummy_metadata( } +def test_get_ipfs_hash_from_uri() -> None: + """Test `get_ipfs_hash_from_uri` method""" + + assert get_ipfs_hash_from_uri("ipfs://SOME_HASH") == "SOME_HASH" + + +def test_verify_component_dependencies_no_dep_found_locally() -> None: + """Test `verify_component_dependencies`""" + + with mock.patch( + "autonomy.chain.utils.resolve_component_id", return_value=get_dummy_metadata() + ), pytest.raises( + DependencyError, + match="On chain dependency with id 0 and public ID valory/package:any not found in the local package configuration", + ): + verify_component_dependencies( + ledger_api=mock.MagicMock(), + contract_address="0xdummy_contract", + dependencies=[ + 0, + ], + package_configuration=mock.MagicMock(package_dependencies=[]), + ) + + +def test_verify_component_dependencies_no_dep_found_on_chain() -> None: + """Test `verify_component_dependencies`""" + + with pytest.raises( + DependencyError, + match=re.escape( + "Please provide on chain ID as dependency for following packages; ['author/package:any']" + ), + ): + verify_component_dependencies( + ledger_api=mock.MagicMock(), + contract_address="0xdummy_contract", + dependencies=[], + package_configuration=mock.MagicMock( + package_dependencies=[ + PackageId.from_uri_path("skill/author/package/0.1.0").with_hash( + DUMMY_HASH + ) + ] + ), + ) + + +def test_verify_component_dependencies_hash_dont_match() -> None: + """Test `verify_component_dependencies`""" + + with mock.patch( + "autonomy.chain.utils.resolve_component_id", + return_value=get_dummy_metadata(), + ), pytest.raises( + DependencyError, + match="Package hash does not match for the on chain package and the local package", + ): + verify_component_dependencies( + ledger_api=mock.MagicMock(), + contract_address="0xdummy_contract", + dependencies=[ + 0, + ], + package_configuration=mock.MagicMock( + package_dependencies=[ + PackageId.from_uri_path("skill/valory/package/0.1.0").with_hash( + DUMMY_HASH + ) + ] + ), + ) + + +def test_verify_component_dependencies_multiple_component_with_same_public_id() -> None: + """Test `verify_component_dependencies`""" + + phash_1 = DUMMY_HASH.replace("0", "1") + phash_2 = DUMMY_HASH.replace("0", "2") + + with mock.patch( + "autonomy.chain.utils.resolve_component_id", + side_effect=[ + get_dummy_metadata(code_uri=phash_1), + get_dummy_metadata(code_uri=phash_2), + ], + ): + verify_component_dependencies( + ledger_api=mock.MagicMock(), + contract_address="0xdummy_contract", + dependencies=[0, 1], + package_configuration=mock.MagicMock( + package_dependencies=[ + PackageId.from_uri_path( + "connection/valory/package/0.1.0", + ).with_hash(phash_1), + PackageId.from_uri_path( + "contract/valory/package/0.1.0", + ).with_hash(phash_2), + ] + ), + ) + + +def test_verify_component_dependencies_multiple_component_with_same_public_id_skip_hash_check() -> ( + None +): + """Test `verify_component_dependencies`""" + + phash_1 = DUMMY_HASH.replace("0", "1") + phash_2 = DUMMY_HASH.replace("0", "2") + + with mock.patch( + "autonomy.chain.utils.resolve_component_id", + side_effect=[ + get_dummy_metadata(code_uri=phash_1), + get_dummy_metadata(code_uri=phash_2), + ], + ): + verify_component_dependencies( + ledger_api=mock.MagicMock(), + contract_address="0xdummy_contract", + dependencies=[0, 1], + package_configuration=mock.MagicMock( + package_dependencies=[ + PackageId.from_uri_path( + "connection/valory/package/0.1.0", + ).with_hash(phash_1), + PackageId.from_uri_path( + "contract/valory/package/0.1.0", + ).with_hash(phash_2), + ] + ), + skip_hash_check=True, + ) + + +def test_verify_component_dependencies_multiple_component_with_same_public_id_fail() -> ( + None +): + """Test `verify_component_dependencies`""" + + phash_1 = DUMMY_HASH.replace("0", "1") + phash_2 = DUMMY_HASH.replace("0", "2") + + with mock.patch( + "autonomy.chain.utils.resolve_component_id", + side_effect=[ + get_dummy_metadata(code_uri=phash_1), + get_dummy_metadata(code_uri="phash_2"), + ], + ), pytest.raises( + DependencyError, + match="Package hash does not match for the on chain package and the local package; Dependency=1", + ): + verify_component_dependencies( + ledger_api=mock.MagicMock(), + contract_address="0xdummy_contract", + dependencies=[0, 1], + package_configuration=mock.MagicMock( + package_dependencies=[ + PackageId.from_uri_path( + "connection/valory/package/0.1.0", + ).with_hash(phash_1), + PackageId.from_uri_path( + "contract/valory/package/0.1.0", + ).with_hash(phash_2), + ] + ), + ) + + +def test_verify_service_dependencies_dep_not_found() -> None: + """Test verify `verify_service_dependencies` method""" + + with mock.patch( + "autonomy.chain.utils.resolve_component_id", return_value=get_dummy_metadata() + ), pytest.raises( + DependencyError, + match="On chain ID of the agent does not match with the one in the service configuration", + ): + verify_service_dependencies( + ledger_api=mock.MagicMock(), + contract_address="0xdummy_contract", + agent_id=0, + service_configuration=mock.MagicMock(), + ) + + +def test_verify_service_dependencies_hash_dont_match() -> None: + """Test verify `verify_service_dependencies` method""" + + with mock.patch( + "autonomy.chain.utils.resolve_component_id", return_value=get_dummy_metadata() + ), pytest.raises( + DependencyError, + match="Package hash does not match for the on chain package and the local package", + ): + verify_service_dependencies( + ledger_api=mock.MagicMock(), + contract_address="0xdummy_contract", + agent_id=0, + service_configuration=mock.MagicMock( + agent=PublicId("valory", "package", package_hash=DUMMY_HASH) + ), + ) + + @pytest.mark.parametrize( "public_id_string", [ - "author/package_name:0.1.0", + "author/package_name", "component_type/author/name", "skill/author/name/0.1.0", ], @@ -74,27 +288,3 @@ def test_parse_public_id_from_metadata_fail() -> None: parse_public_id_from_metadata( id_string="public_id", ) - - -def test_resolve_component_id_failures() -> None: - """Test `resolve_component_id` exceptions""" - - with pytest.raises( - FailedToRetrieveComponentMetadata, match="Error connecting to the RPC" - ): - with mock.patch.object( - Contract, "get_instance", side_effect=RequestConnectionError - ): - resolve_component_id( - ledger_api=mock.MagicMock(), contract_address="0xaddress", token_id=1 - ) - - with pytest.raises( - FailedToRetrieveComponentMetadata, match="Error connecting to the IPFS gateway" - ): - with mock.patch.object(Contract, "get_instance"), mock.patch( - "autonomy.chain.utils.r_get", side_effect=RequestConnectionError - ): - resolve_component_id( - ledger_api=mock.MagicMock(), contract_address="0xaddress", token_id=1 - ) diff --git a/tests/test_autonomy/test_cli/test_analyse/test_abci/test_docstring_generator.py b/tests/test_autonomy/test_cli/test_analyse/test_abci/test_docstring_generator.py index 36a870abdb..d06cb0cb3d 100644 --- a/tests/test_autonomy/test_cli/test_analyse/test_abci/test_docstring_generator.py +++ b/tests/test_autonomy/test_cli/test_analyse/test_abci/test_docstring_generator.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- # ------------------------------------------------------------------------------ # -# Copyright 2022 Valory AG +# Copyright 2022-2023 Valory AG # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -27,7 +27,7 @@ from aea.configurations.constants import PACKAGES -from packages.valory.skills.hello_world_abci import rounds +from packages.valory.skills.offend_abci import rounds from tests.conftest import ROOT_DIR from tests.test_autonomy.test_cli.base import BaseCliTest @@ -38,7 +38,7 @@ class TestDocstrings(BaseCliTest): rounds_file_original: Path rounds_file_temp: Path - skill_name: str = "hello_world_abci" + skill_name: str = "offend_abci" cli_options: Tuple[str, ...] = ("analyse", "docstrings") rounds_file = Path(PACKAGES, "valory", "skills", skill_name, "rounds.py") @@ -76,10 +76,7 @@ def _corrupt_round_file( ) -> None: """Corrupt a round file.""" - string_to_replace = """4. ResetAndPauseRound - - done: 1. - - no majority: 0. - - reset timeout: 0.\n""" + string_to_replace = """1. FinishedOffendRound\n""" rounds_file_content = self.rounds_file_original.read_text() rounds_file_content = rounds_file_content.replace(string_to_replace, "") diff --git a/tests/test_autonomy/test_cli/test_analyse/test_abci/test_docstrings.py b/tests/test_autonomy/test_cli/test_analyse/test_abci/test_docstrings.py index 880f5d2b85..10799d985c 100644 --- a/tests/test_autonomy/test_cli/test_analyse/test_abci/test_docstrings.py +++ b/tests/test_autonomy/test_cli/test_analyse/test_abci/test_docstrings.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- # ------------------------------------------------------------------------------ # -# Copyright 2022 Valory AG +# Copyright 2022-2023 Valory AG # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -28,45 +28,32 @@ docstring_abci_app, ) -from packages.valory.skills.hello_world_abci.rounds import HelloWorldAbciApp +from packages.valory.skills.offend_abci.rounds import OffendAbciApp def test_docstring_abci_app() -> None: """Test docstring_abci_app""" - expected = """\"\"\"HelloWorldAbciApp - - Initial round: RegistrationRound - - Initial states: {RegistrationRound} - - Transition states: - 0. RegistrationRound - - done: 1. - 1. CollectRandomnessRound - - done: 2. - - no majority: 1. - - round timeout: 1. - 2. SelectKeeperRound - - done: 3. - - no majority: 0. - - round timeout: 0. - 3. PrintMessageRound - - done: 4. - - round timeout: 0. - 4. ResetAndPauseRound - - done: 1. - - no majority: 0. - - reset timeout: 0. - - Final states: {} - - Timeouts: - round timeout: 30.0 - reset timeout: 30.0 + expected = """\"\"\"OffendAbciApp + + Initial round: OffendRound + + Initial states: {OffendRound} + + Transition states: + 0. OffendRound + - done: 1. + - no majority: 0. + - round timeout: 0. + 1. FinishedOffendRound + + Final states: {FinishedOffendRound} + + Timeouts: + round timeout: 30.0 \"\"\"""" - docstring = docstring_abci_app(HelloWorldAbciApp) + docstring = docstring_abci_app(OffendAbciApp) differences = "\n".join(difflib.unified_diff(docstring.split(), expected.split())) assert not differences, differences @@ -78,14 +65,14 @@ def test_compare_docstring_content() -> None: assert compare_docstring_content("", "", "") == (False, "") # identical - no update - docstring = docstring_abci_app(HelloWorldAbciApp) - abci_app_name = HelloWorldAbciApp.__name__ - file_content = Path(inspect.getfile(HelloWorldAbciApp)).read_text() + docstring = docstring_abci_app(OffendAbciApp) + abci_app_name = OffendAbciApp.__name__ + file_content = Path(inspect.getfile(OffendAbciApp)).read_text() result = compare_docstring_content(file_content, docstring, abci_app_name) assert result == (True, file_content) # mutated - update - mutated_content = file_content.replace("Initial round: RegistrationRound", "") + mutated_content = file_content.replace("Initial round: OffendRound", "") assert not mutated_content == file_content result = compare_docstring_content(mutated_content, docstring, abci_app_name) assert result == (True, file_content) diff --git a/tests/test_autonomy/test_cli/test_analyse/test_check_handlers.py b/tests/test_autonomy/test_cli/test_analyse/test_check_handlers.py index 8c15230166..45288ace94 100644 --- a/tests/test_autonomy/test_cli/test_analyse/test_check_handlers.py +++ b/tests/test_autonomy/test_cli/test_analyse/test_check_handlers.py @@ -46,7 +46,6 @@ "abstract_abci", "counter", "counter_client", - "hello_world_abci", ) diff --git a/tests/test_autonomy/test_cli/test_analyse/test_specs.py b/tests/test_autonomy/test_cli/test_analyse/test_specs.py index 11e77aad3c..8f8b69a446 100644 --- a/tests/test_autonomy/test_cli/test_analyse/test_specs.py +++ b/tests/test_autonomy/test_cli/test_analyse/test_specs.py @@ -58,8 +58,8 @@ def setup(self) -> None: """Setup test method.""" super().setup() - self.app_name = "HelloWorldAbciApp" - self.skill_path = Path(PACKAGES, "valory", "skills", "hello_world_abci") + self.app_name = "OffendAbciApp" + self.skill_path = Path(PACKAGES, "valory", "skills", "offend_abci") module_name = ".".join((*self.skill_path.parts, "rounds")) module = importlib.import_module(module_name) @@ -173,9 +173,9 @@ class TestCheckSpecs(BaseCliTest): """Test `check-app-specs` command.""" cli_options: Tuple[str, ...] = ("analyse", "fsm-specs") - skill_path = Path(PACKAGES, "valory", "skills", "hello_world_abci") + skill_path = Path(PACKAGES, "valory", "skills", "offend_abci") module_name = ".".join(skill_path.parts) - app_name = "HelloWorldAbciApp" + app_name = "OffendAbciApp" cls_name = ".".join([module_name, app_name]) packages_dir: Path @@ -207,9 +207,8 @@ def _corrupt_spec_file( ) -> None: """Corrupt spec file to fail the check.""" content = self.specification_path.read_text() - content = content.replace( - "(SelectKeeperRound, ROUND_TIMEOUT): RegistrationRound\n", "" - ) + content = content.replace("(OffendRound, ROUND_TIMEOUT): OffendRound\n", "") + content = content.replace("- ROUND_TIMEOUT\n", "") self.specification_path.write_text(content) def test_one_pass( diff --git a/tests/test_autonomy/test_cli/test_analyse/test_verify_service.py b/tests/test_autonomy/test_cli/test_analyse/test_verify_service.py index 75f8fcc05f..c5b6423746 100644 --- a/tests/test_autonomy/test_cli/test_analyse/test_verify_service.py +++ b/tests/test_autonomy/test_cli/test_analyse/test_verify_service.py @@ -34,6 +34,7 @@ ) from aea.helpers.cid import to_v0 from aea_cli_ipfs.ipfs_utils import IPFSDaemon, IPFSTool +from requests.exceptions import ConnectionError as RequestConnectionError from autonomy.analyse.service import ServiceAnalyser from autonomy.configurations.base import Service @@ -70,60 +71,110 @@ def get_dummy_service_config() -> Dict: } -def get_dummy_overrides_skill() -> Dict: +def get_dummy_overrides_skill(env_vars_with_name: bool = False) -> Dict: """Returns dummy skill overrides.""" + if env_vars_with_name: + return { + "public_id": "valory/abci_skill:0.1.0", + "type": "skill", + "models": { + "params": { + "args": { + "message": "${MESSAGE:str:Hello, World!}", + "reset_pause_duration": "${RESET_PAUSE_DURATION:int:10}", + "setup": { + "safe_contract_address": "${SAFE_CONTRACT_ADDRESS:str:0xaddress}", + "all_participants": '${ALL_PARTICIPANTS:list:["0x"]}', + "consensus_threshold": "${CONSENSUS_THRESHOLD:int:null}", + }, + "tendermint_url": "${TENDERMINT_URL:str:http://localhost}", + "tendermint_com_url": "${TENDERMINT_COM_URL:str:http://localhost}", + "tendermint_p2p_url": "${TENDERMINT_P2P_URL:str:http://localhost}", + "service_registry_address": "${SERVICE_REGISTRY_ADDRESS:str:0xaddress}", + "share_tm_config_on_startup": "${SHARE_TM_CONFIG_ON_STARTUP:bool:false}", + "on_chain_service_id": "${ON_CHAIN_SERVICE_ID:int:null}", + }, + } + }, + } return { "public_id": "valory/abci_skill:0.1.0", "type": "skill", "models": { "params": { "args": { - "message": "Hello, World!", - "reset_pause_duration": 10, + "message": "${str:Hello, World!}", + "reset_pause_duration": "${int:10}", "setup": { - "safe_contract_address": "0xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", - "all_participants": ["0x"], - "consensus_threshold": None, + "safe_contract_address": "${str:0xaddress}", + "all_participants": '${list:["0x"]}', + "consensus_threshold": "${int:null}", }, - "tendermint_url": "tendermint_url", - "tendermint_com_url": "tendermint_com_url", - "tendermint_p2p_url": "tendermint_p2p_url", - "service_registry_address": "service_registry_address", - "share_tm_config_on_startup": "share_tm_config_on_startup", - "on_chain_service_id": "on_chain_service_id", + "tendermint_url": "${str:http://localhost}", + "tendermint_com_url": "${str:http://localhost}", + "tendermint_p2p_url": "${str:http://localhost}", + "service_registry_address": "${str:0xaddress}", + "share_tm_config_on_startup": "${bool:false}", + "on_chain_service_id": "${int:null}", }, } }, } -def get_dummy_overrides_ledger_connection() -> Dict: +def get_dummy_overrides_ledger_connection(env_vars_with_name: bool = False) -> Dict: """Returns dummy connection overrides""" + if env_vars_with_name: + return { + "public_id": "valory/ledger:0.1.0", + "type": "connection", + "config": { + "ledger_apis": { + "ethereum": { + "address": "${ADDRESS:str:address}", + "chain_id": "${CHAIN_ID:int:1}", + "poa_chain": "${POA_CHAIN:bool:false}", + "default_gas_price_strategy": "${DEFAULT_GAS_PRICE_STRATEGY:str:eip1559}", + } + } + }, + } return { "public_id": "valory/ledger:0.1.0", "type": "connection", "config": { "ledger_apis": { "ethereum": { - "address": "address", - "chain_id": 1, - "poa_chain": False, - "default_gas_price_strategy": "eip1559", + "address": "${str:address}", + "chain_id": "${int:1}", + "poa_chain": "${bool:false}", + "default_gas_price_strategy": "${str:eip1559}", } } }, } -def get_dummy_overrides_abci_connection() -> Dict: +def get_dummy_overrides_abci_connection(env_vars_with_name: bool = False) -> Dict: """Returns dummy connection overrides""" + if env_vars_with_name: + return { + "public_id": "valory/abci:0.1.0", + "type": "connection", + "config": { + "host": "${ABCI_HOST:str:host}", + "port": "${ABCI_PORT:str:port}", + "use_tendermint": "${ABCI_USE_TENDERMINT:bool:false}", + }, + } + return { "public_id": "valory/abci:0.1.0", "type": "connection", "config": { - "host": "host", - "port": "port", - "use_tendermint": "use_tendermint", + "host": "${str:host}", + "port": "${str:port}", + "use_tendermint": "${bool:false}", }, } @@ -216,6 +267,12 @@ def get_dummy_skill_config() -> Dict: "tendermint_p2p_url": "localhost:26656", "tendermint_url": "http://localhost:26657", "tx_timeout": 10, + "use_termination": False, + "use_slashing": False, + "slash_cooldown_hours": 3, + "slash_threshold_amount": 10_000_000_000_000_000, + "light_slash_unit_amount": 5_000_000_000_000_000, + "serious_slash_unit_amount": 8_000_000_000_000_000, }, "class_name": "Params", }, @@ -340,13 +397,83 @@ def patch_get_on_chain_service_id() -> mock._patch: ) -class TestCheckRequiredOverrides(BaseAnalyseServiceTest): - """Test override verification.""" +class TestVerifySkillConfig(BaseAnalyseServiceTest): + """Test verify overrides method.""" + + def test_abci_skill_not_found(self) -> None: + """Test run.""" + + skill_config = get_dummy_skill_config() + skill_config["skills"] = [] + with self.patch_loader( + service_data=[ + get_dummy_service_config(), + get_dummy_overrides_skill(env_vars_with_name=True), + ], + agent_data=[get_dummy_agent_config(), get_dummy_overrides_skill()], + skill_data=skill_config, + ), self.patch_ipfs_tool([]): + result = self.run_cli(commands=self.public_id_option) + + assert result.exit_code == 1, result.stdout + assert "Chained ABCI skill package not found" in result.stderr + + def test_params_model_not_found(self) -> None: + """Test run.""" + + skill_config = get_dummy_skill_config() + del skill_config["models"]["params"] + + with self.patch_loader( + service_data=[ + get_dummy_service_config(), + get_dummy_overrides_skill(env_vars_with_name=True), + ], + agent_data=[get_dummy_agent_config(), get_dummy_overrides_skill()], + skill_data=skill_config, + ), self.patch_ipfs_tool([]): + result = self.run_cli(commands=self.public_id_option) + + assert result.exit_code == 1, result.stdout + assert ( + "The chained ABCI skill `valory/abci_skill:0.1.0` does not contain `params` model" + in result.stderr + ) + + +class TestCheckRequiredAgentOverrides(BaseAnalyseServiceTest): + """Test agent override verification.""" + + def test_missing_override(self) -> None: + """Test missing override run.""" + + skill_config_service = get_dummy_overrides_skill(env_vars_with_name=True) + skill_config_agent = get_dummy_overrides_skill() + + del skill_config_agent["models"]["params"]["args"]["setup"] + + with self.patch_loader( + service_data=[get_dummy_service_config(), skill_config_service], + agent_data=[get_dummy_agent_config(), skill_config_agent], + skill_data=get_dummy_skill_config(), + ), self.patch_ipfs_tool([]): + result = self.run_cli(commands=self.public_id_option) + + assert result.exit_code == 1, result.stdout + assert ( + "Error: Agent overrides validation failed with following errors" + "\n\t- ABCI Skill `valory/abci_skill:0.1.0` override validation failed; Following properties are require but missing 'setup'\n" + in result.stderr + ), result.stdout + + +class TestCheckRequiredServiceOverrides(BaseAnalyseServiceTest): + """Test service override verification.""" def test_abci_skill_params_not_defined(self) -> None: """Test successful run.""" - skill_config = get_dummy_overrides_skill() + skill_config = get_dummy_overrides_skill(env_vars_with_name=True) del skill_config["models"]["params"] with self.patch_loader( @@ -358,14 +485,15 @@ def test_abci_skill_params_not_defined(self) -> None: assert result.exit_code == 1, result.stdout assert ( - "ABCI skill validation failed; 'params' is a required property" + "Service overrides validation failed with following errors" + "\n\t- ABCI Skill `valory/abci_skill:0.1.0` override validation failed; Following properties are require but missing 'params'\n" in result.stderr ), result.stdout def test_abci_skill_required_arg_not_defined(self, caplog: Any) -> None: """Test successful run.""" - skill_config = get_dummy_overrides_skill() + skill_config = get_dummy_overrides_skill(env_vars_with_name=True) del skill_config["models"]["params"]["args"]["tendermint_url"] with self.patch_loader( @@ -375,9 +503,9 @@ def test_abci_skill_required_arg_not_defined(self, caplog: Any) -> None: ), self.patch_ipfs_tool([]), caplog.at_level(logging.WARNING): result = self.run_cli(commands=self.public_id_option) - assert result.exit_code == 0, result.stdout + assert result.exit_code == 0, result.stderr assert ( - "ServiceAnalyser:service.py:284 (agent, valory/dummy_agent:0.1.0) contains configuration which is missing from (service, valory/dummy_service:0.1.0)" + "(agent, valory/dummy_agent:0.1.0) contains configuration which is missing from (service, valory/dummy_service:0.1.0)\n\tPath: models.params.args\n\tMissing parameters: {'tendermint_url'}" in caplog.text ) assert "Path: models.params.args" in caplog.text @@ -399,20 +527,22 @@ def test_abci_skill_setup_param_not_defined(self) -> None: assert result.exit_code == 1, result.stdout assert ( - "Error: ABCI skill validation failed; 'all_participants' is a required property" + "Service overrides validation failed with following errors\n\t- ABCI Skill `valory/abci_skill:0.1.0` override validation failed; Following properties are require but missing 'all_participants'\n" in result.stderr ) def test_ledger_connection_ledger_not_defined(self) -> None: """Test successful run.""" - connection_config = get_dummy_overrides_ledger_connection() + connection_config = get_dummy_overrides_ledger_connection( + env_vars_with_name=True + ) del connection_config["config"]["ledger_apis"]["ethereum"] with self.patch_loader( service_data=[ get_dummy_service_config(), - get_dummy_overrides_skill(), + get_dummy_overrides_skill(env_vars_with_name=True), connection_config, ], agent_data=[get_dummy_agent_config(), get_dummy_overrides_skill()], @@ -422,14 +552,17 @@ def test_ledger_connection_ledger_not_defined(self) -> None: assert result.exit_code == 1, result.stdout assert ( - "Error: Ledger connection validation failed; {} does not have enough properties" + "Service overrides validation failed with following errors" + "\n\t- (connection, valory/ledger:0.1.0) override needs at least one ledger API definition" in result.stderr ) def test_ledger_connection_unknown_ledger_defined(self, caplog: Any) -> None: """Test successful run.""" - connection_config = get_dummy_overrides_ledger_connection() + connection_config = get_dummy_overrides_ledger_connection( + env_vars_with_name=True + ) connection_config["config"]["ledger_apis"]["solana"] = connection_config[ "config" ]["ledger_apis"]["ethereum"] @@ -437,7 +570,7 @@ def test_ledger_connection_unknown_ledger_defined(self, caplog: Any) -> None: with self.patch_loader( service_data=[ get_dummy_service_config(), - get_dummy_overrides_skill(), + get_dummy_overrides_skill(env_vars_with_name=True), connection_config, ], agent_data=[get_dummy_agent_config(), get_dummy_overrides_skill()], @@ -446,7 +579,10 @@ def test_ledger_connection_unknown_ledger_defined(self, caplog: Any) -> None: result = self.run_cli(commands=self.public_id_option) assert result.exit_code == 1, result.stdout - assert "Unknown ledger configuration found with name `solana`" in caplog.text + assert ( + "Following unknown ledgers found in the (connection, valory/ledger:0.1.0) override\n\t- solana\n" + in caplog.text + ) def test_ledger_connection_param_not_defined(self) -> None: """Test successful run.""" @@ -467,7 +603,8 @@ def test_ledger_connection_param_not_defined(self) -> None: assert result.exit_code == 1, result.stdout assert ( - "Error: Ledger connection validation failed; 'address' is a required property" + "Service overrides validation failed with following errors" + "\n\t- Ledger connection validation failed; Following properties are require but missing 'address'\n" in result.stderr ) @@ -490,11 +627,105 @@ def test_abci_connection_setup_param_not_defined(self) -> None: assert result.exit_code == 1, result.stdout assert ( - "Error: ABCI connection validation failed; 'host' is a required property" + "Service overrides validation failed with following errors" + "\n\t- ABCI connection validation failed; Following properties are require but missing 'host'\n" in result.stderr ) +class TestEnvVarValidation(BaseAnalyseServiceTest): + """Test service override verification.""" + + def test_list_var_validation(self) -> None: + """Test agent var validation.""" + + skill_config = get_dummy_overrides_skill() + skill_config["models"]["params"]["args"]["messages"] = [ + {"text": "${str:hello}"} + ] + + with self.patch_loader( + service_data=[ + get_dummy_service_config(), + get_dummy_overrides_skill(env_vars_with_name=True), + ], + agent_data=[get_dummy_agent_config(), skill_config], + skill_data=get_dummy_skill_config(), + ), self.patch_ipfs_tool([]): + result = self.run_cli(commands=self.public_id_option) + + assert result.exit_code == 0, result.stdout + + def test_agent_var_validation(self) -> None: + """Test agent var validation.""" + + skill_config = get_dummy_overrides_skill() + skill_config["models"]["params"]["args"]["message"] = "Hello, World!" + + with self.patch_loader( + service_data=[ + get_dummy_service_config(), + get_dummy_overrides_skill(env_vars_with_name=True), + ], + agent_data=[get_dummy_agent_config(), skill_config], + skill_data=get_dummy_skill_config(), + ), self.patch_ipfs_tool([]): + result = self.run_cli(commands=self.public_id_option) + + assert result.exit_code == 1, result.stdout + assert ( + "(skill, valory/abci_skill:0.1.0) envrionment variable validation failed with following error\n\t- " + "`models.params.args.message` needs environment variable defined in following format ${ENV_VAR_NAME:DATA_TYPE:DEFAULT_VALUE}\n" + in result.stderr + ), result.stdout + + def test_var_type_validation(self) -> None: + """Test var type validation.""" + + skill_config = get_dummy_overrides_skill() + skill_config["models"]["params"]["args"]["tendermint_url"] = None + + with self.patch_loader( + service_data=[ + get_dummy_service_config(), + get_dummy_overrides_skill(env_vars_with_name=True), + ], + agent_data=[get_dummy_agent_config(), skill_config], + skill_data=get_dummy_skill_config(), + ), self.patch_ipfs_tool([]): + result = self.run_cli(commands=self.public_id_option) + + assert result.exit_code == 1, result.stdout + assert ( + "(skill, valory/abci_skill:0.1.0) envrionment variable validation failed with following error" + "\n\t- `models.params.args.tendermint_url` needs to be defined as a environment variable" + in result.stderr + ), result.stdout + + def test_loading(self) -> None: + """Test var type validation.""" + + skill_config = get_dummy_overrides_skill() + skill_config["models"]["params"]["args"]["tendermint_url"] = "${int:hello}" + + with self.patch_loader( + service_data=[ + get_dummy_service_config(), + get_dummy_overrides_skill(env_vars_with_name=True), + ], + agent_data=[get_dummy_agent_config(), skill_config], + skill_data=get_dummy_skill_config(), + ), self.patch_ipfs_tool([]): + result = self.run_cli(commands=self.public_id_option) + + assert result.exit_code == 1, result.stdout + assert ( + "(skill, valory/abci_skill:0.1.0) envrionment variable validation failed with following error" + "\n\t- `models.params.args.tendermint_url` validation failed with following error; Cannot convert string `hello` to type `int`" + in result.stderr + ), result.stdout + + class TestCheckAgentDependenciesPublished(BaseAnalyseServiceTest): """Test `check_agent_package_published` method.""" @@ -502,7 +733,10 @@ def test_dependency_not_found(self) -> None: """Test failure.""" with self.patch_loader( - service_data=[get_dummy_service_config(), get_dummy_overrides_skill()], + service_data=[ + get_dummy_service_config(), + get_dummy_overrides_skill(env_vars_with_name=True), + ], agent_data=[get_dummy_agent_config(), get_dummy_overrides_skill()], skill_data=get_dummy_skill_config(), is_remote=True, @@ -521,17 +755,17 @@ def test_dependency_not_found(self) -> None: assert "agent: valory/dummy_agent:0.1.0" in result.stderr -class TestVerifyOverrides(BaseAnalyseServiceTest): +class TestVerifyCrossOverrides(BaseAnalyseServiceTest): """Test verify overrides method.""" - def test_missing_override(self) -> None: + def test_overrides_missing_from_agent(self) -> None: """Test missing override section from agent config.""" with self.patch_loader( service_data=[ get_dummy_service_config(), - get_dummy_overrides_skill(), - get_dummy_overrides_ledger_connection(), + get_dummy_overrides_skill(env_vars_with_name=True), + get_dummy_overrides_ledger_connection(env_vars_with_name=True), ], agent_data=[get_dummy_agent_config(), get_dummy_overrides_skill()], skill_data=get_dummy_skill_config(), @@ -540,9 +774,28 @@ def test_missing_override(self) -> None: assert result.exit_code == 1, result.stdout assert ( - "Error: Service config has an overrides which are not defined in the agent config;" - " packages with missing overrides={PackageId(connection, valory/ledger:0.1.0)}" - in result.stderr + "Overrides with following component IDs are defined in the service configuration but not in the agent configuration" + "\n\t- (connection, valory/ledger:0.1.0)\n" in result.stderr + ) + + def test_overrides_missing_from_service(self, caplog: Any) -> None: + """Test missing override section from service config.""" + + with self.patch_loader( + service_data=[get_dummy_service_config()], + agent_data=[get_dummy_agent_config(), get_dummy_overrides_skill()], + skill_data=get_dummy_skill_config(), + ), self.patch_ipfs_tool( + [] + ), self.patch_validate_service_overrides(), caplog.at_level( + logging.WARNING + ): + result = self.run_cli(commands=self.public_id_option) + + assert result.exit_code == 0, result.stdout + assert ( + "Overrides with following component IDs are defined in the agent configuration but not in the service configuration" + "\n\t- (skill, valory/abci_skill:0.1.0)" in caplog.text ) @@ -574,15 +827,44 @@ def test_on_chain_status_check(self, caplog: Any) -> None: in caplog.text ) + def test_on_chain_status_check_rpc_failure(self) -> None: + """Test `check_on_chain_state` RPC connection failure""" + + with self.patch_loader( + service_data=[get_dummy_service_config(), get_dummy_overrides_skill()], + agent_data=[get_dummy_agent_config(), get_dummy_overrides_skill()], + skill_data=get_dummy_skill_config(), + is_remote=True, + ), mock.patch( + "autonomy.analyse.service.get_service_info", + side_effect=RequestConnectionError, + ), self.patch_ipfs_tool( + [] + ), self.patch_ipfs_daemon_is_started( + return_value=True, + ), self.patch_get_on_chain_service_id(): + result = self.run_cli(commands=self.token_id_option) + + assert result.exit_code == 1, result.stdout + assert ( + "On chain service validation failed, could not connect to the RPC" + in result.stderr + ) + class TestCheckSuccessful(BaseAnalyseServiceTest): """Test a successful check""" - def test_run(self) -> None: + def test_run(self, caplog: Any) -> None: """Test run.""" - skill_config = get_dummy_overrides_skill() + skill_config = get_dummy_overrides_skill(env_vars_with_name=True) models = skill_config.pop("models") + skill_config_original = get_dummy_skill_config() + skill_config_original["models"]["benchmark_tool"] = { + "args": {"log_dir": "/logs"} + } + for i in range(4): skill_config[i] = {"models": deepcopy(models)} @@ -590,8 +872,8 @@ def test_run(self) -> None: service_data=[ get_dummy_service_config(), skill_config, - get_dummy_overrides_abci_connection(), - get_dummy_overrides_ledger_connection(), + get_dummy_overrides_abci_connection(env_vars_with_name=True), + get_dummy_overrides_ledger_connection(env_vars_with_name=True), ], agent_data=[ get_dummy_agent_config(), @@ -599,7 +881,7 @@ def test_run(self) -> None: get_dummy_overrides_abci_connection(), get_dummy_overrides_ledger_connection(), ], - skill_data=get_dummy_skill_config(), + skill_data=skill_config_original, is_remote=True, ), self.patch_ipfs_tool( pins=list( @@ -618,8 +900,14 @@ def test_run(self) -> None: ), self.patch_get_on_chain_service_id(), mock.patch( "autonomy.analyse.service.get_service_info", return_value=(None, 4, None), + ), caplog.at_level( + logging.WARNING ): result = self.run_cli(commands=self.token_id_option) assert result.exit_code == 0, result.stderr assert "Service is ready to be deployed" in result.output + assert ( + "valory/termination_abci:any is not defined as a dependency" in caplog.text + ) + assert "valory/slashing_abci:any is not defined as a dependency" in caplog.text diff --git a/tests/test_autonomy/test_cli/test_build_image.py b/tests/test_autonomy/test_cli/test_build_image.py index dc1143a6d2..7bfef31488 100644 --- a/tests/test_autonomy/test_cli/test_build_image.py +++ b/tests/test_autonomy/test_cli/test_build_image.py @@ -18,7 +18,7 @@ # ------------------------------------------------------------------------------ """Test build image.""" -import json + import os from pathlib import Path from random import choices @@ -34,7 +34,7 @@ from autonomy.configurations.base import Service from autonomy.constants import DEFAULT_DOCKER_IMAGE_AUTHOR -from tests.conftest import get_file_from_tag, skip_docker_tests +from tests.conftest import skip_docker_tests from tests.test_autonomy.base import get_dummy_service_config from tests.test_autonomy.test_cli.base import BaseCliTest @@ -59,8 +59,8 @@ def setup(self) -> None: public_id=PublicId(author="valory", name="test_abci", version="0.1.0"), ) - packages_json = json.loads(get_file_from_tag("packages/packages.json")) - package_hash = packages_json["dev"][self.package_id.to_uri_path] + # TODO: Revert after release + package_hash = "bafybeibe6kgnwkuhcydk5gr3wvsybdlc7gfuzt2ia24czudsvxlbmdlrwe" self.package_id = self.package_id.with_hash(package_hash=package_hash) os.chdir(self.t) diff --git a/tests/test_autonomy/test_cli/test_deploy/test_build/test_deployment.py b/tests/test_autonomy/test_cli/test_deploy/test_build/test_deployment.py index aad3b90e06..589b2fc845 100644 --- a/tests/test_autonomy/test_cli/test_deploy/test_build/test_deployment.py +++ b/tests/test_autonomy/test_cli/test_deploy/test_build/test_deployment.py @@ -19,6 +19,7 @@ """Test deployment command.""" +import json import os import shutil from pathlib import Path @@ -27,13 +28,14 @@ import yaml from aea.cli.utils.config import get_default_author_from_cli_config -from aea.configurations.constants import PACKAGES +from aea.configurations.constants import DEFAULT_ENV_DOTFILE, PACKAGES from aea_test_autonomy.configurations import ( ETHEREUM_ENCRYPTED_KEYS, ETHEREUM_ENCRYPTION_PASSWORD, ) from autonomy.constants import DEFAULT_BUILD_FOLDER, DEFAULT_DOCKER_IMAGE_AUTHOR +from autonomy.deploy.base import ServiceBuilder from autonomy.deploy.constants import ( DEBUG, DEPLOYMENT_AGENT_KEY_DIRECTORY_SCHEMA, @@ -57,9 +59,8 @@ class BaseDeployBuildTest(BaseCliTest): """Test `autonomy deply build deployment` command.""" cli_options: Tuple[str, ...] = ("deploy", "build") - service_id: str = "valory/oracle_hardhat" - keys_file: Path + spec: ServiceBuilder def setup(self) -> None: """Setup test method.""" @@ -72,10 +73,15 @@ def setup(self) -> None: ) shutil.copytree( - self.t / PACKAGES / "valory" / "services" / "hello_world", - self.t / "hello_world", + self.t / PACKAGES / "valory" / "services" / "register_reset", + self.t / "register_reset", ) - os.chdir(self.t / "hello_world") + with OS_ENV_PATCH: + self.spec = ServiceBuilder.from_dir( + self.t / "register_reset", + self.keys_file, + ) + os.chdir(self.t / "register_reset") @staticmethod def load_kubernetes_config( @@ -95,8 +101,8 @@ def check_kubernetes_build(cls, build_dir: Path) -> None: child in build_tree for child in ["persistent_storage", "build.yaml"] ) - @staticmethod def load_and_check_docker_compose_file( + self, path: Path, ) -> Dict: """Load docker compose config.""" @@ -111,8 +117,8 @@ def load_and_check_docker_compose_file( [ service in docker_compose["services"] for service in [ - *map(lambda i: f"abci{i}", range(4)), - *map(lambda i: f"node0{i}", range(4)), + *map(lambda i: self.spec.get_abci_container_name(i), range(4)), + *map(lambda i: self.spec.get_tm_container_name(i), range(4)), ] ] ) @@ -186,7 +192,7 @@ def test_docker_compose_build_with_testnet( ) assert result.exit_code == 0, result.output - assert (build_dir / "nodes").exists() + assert (build_dir / "nodes").exists(), result.stderr def test_docker_compose_build_log_level( self, @@ -218,10 +224,16 @@ def test_docker_compose_build_log_level( ) assert ( - f"LOG_LEVEL={DEBUG}" in docker_compose["services"]["abci0"]["environment"] + f"LOG_LEVEL={DEBUG}" + in docker_compose["services"][self.spec.get_abci_container_name(0)][ + "environment" + ] ) assert ( - f"LOG_LEVEL={DEBUG}" in docker_compose["services"]["node0"]["environment"] + f"LOG_LEVEL={DEBUG}" + in docker_compose["services"][self.spec.get_tm_container_name(0)][ + "environment" + ] ) def test_docker_compose_build_dev( @@ -260,12 +272,21 @@ def test_docker_compose_build_dev( assert ( f"{ROOT_DIR}:/home/ubuntu/packages:rw" - in docker_compose["services"]["abci0"]["volumes"] + in docker_compose["services"][self.spec.get_abci_container_name(index=0)][ + "volumes" + ] + ) + assert ( + f"{ROOT_DIR}:/open-aea" + in docker_compose["services"][self.spec.get_abci_container_name(index=0)][ + "volumes" + ] ) - assert f"{ROOT_DIR}:/open-aea" in docker_compose["services"]["abci0"]["volumes"] assert ( f"{ROOT_DIR}:/open-autonomy" - in docker_compose["services"]["abci0"]["volumes"] + in docker_compose["services"][self.spec.get_abci_container_name(index=0)][ + "volumes" + ] ) def test_docker_compose_password( @@ -287,12 +308,14 @@ def test_docker_compose_password( ) build_dir = self.t / DEFAULT_BUILD_FOLDER - - assert result.exit_code == 0, result.output + assert result.exit_code == 0, result.stderr + assert ( + "WARNING: `--password` flag has been deprecated, use `OPEN_AUTONOMY_PRIVATE_KEY_PASSWORD` to export the password value" + in result.stdout + ) assert build_dir.exists() build_dir = self.t / DEFAULT_BUILD_FOLDER - assert result.exit_code == 0, result.output assert build_dir.exists() @@ -300,8 +323,6 @@ def test_docker_compose_password( with open(docker_compose_file, "r", encoding="utf-8") as fp: docker_compose = yaml.safe_load(fp) - agents = int(len(docker_compose["services"]) / 2) - def _file_check(n: int) -> bool: return ( build_dir @@ -309,16 +330,19 @@ def _file_check(n: int) -> bool: / DEPLOYMENT_AGENT_KEY_DIRECTORY_SCHEMA.format(agent_n=n) ).exists() + agents = int(len(docker_compose["services"]) / 2) assert all(_file_check(i) for i in range(agents)) for x in range(agents): env = dict( [ f.split("=") - for f in docker_compose["services"][f"abci{x}"]["environment"] + for f in docker_compose["services"][ + self.spec.get_abci_container_name(x) + ]["environment"] ] ) assert "AEA_PASSWORD" in env.keys() - assert env["AEA_PASSWORD"] == ETHEREUM_ENCRYPTION_PASSWORD + assert env["AEA_PASSWORD"] == "$OPEN_AUTONOMY_PRIVATE_KEY_PASSWORD" def test_include_acn_and_hardhat_nodes( self, @@ -425,7 +449,9 @@ def test_docker_compose_build_image_author_flag_default( ) assert ( - docker_compose["services"]["abci0"]["image"].split("/")[0] + docker_compose["services"][self.spec.get_abci_container_name(0)][ + "image" + ].split("/")[0] == get_default_author_from_cli_config() or DEFAULT_DOCKER_IMAGE_AUTHOR ) @@ -463,7 +489,10 @@ def test_docker_compose_build_image_author_flag_custom( ) assert ( - docker_compose["services"]["abci0"]["image"].split("/")[0] == image_author + docker_compose["services"][self.spec.get_abci_container_name(0)][ + "image" + ].split("/")[0] + == image_author ) @@ -573,6 +602,10 @@ def test_kubernetes_build_password( ) assert result.exit_code == 0, result.output + assert ( + "WARNING: `--password` flag has been deprecated, use `OPEN_AUTONOMY_PRIVATE_KEY_PASSWORD` to export the password value" + in result.stdout + ) assert build_dir.exists() kubernetes_config = self.load_kubernetes_config( @@ -585,7 +618,7 @@ def test_kubernetes_build_password( except (KeyError, IndexError): continue - assert agent_vars["AEA_PASSWORD"] == ETHEREUM_ENCRYPTION_PASSWORD + assert agent_vars["AEA_PASSWORD"] == "" assert all( ( @@ -698,11 +731,20 @@ def setup(self) -> None: super().setup() service_data = get_dummy_service_config(file_number=1) - service_data[0]["deployment"] = {"agent": {"ports": {0: {8080: 8081}}}} + service_data[0]["deployment"] = { + "agent": {"ports": {0: {8080: 8081}}}, + "tendermint": {"ports": {0: {26656: 26666}}}, + } with open("./service.yaml", "w+") as fp: yaml.dump_all(service_data, fp) + with OS_ENV_PATCH: + self.spec = ServiceBuilder.from_dir( + self.t / "register_reset", + self.keys_file, + ) + def test_expose_agent_ports_docker_compose(self) -> None: """Test expose agent ports""" @@ -722,12 +764,16 @@ def test_expose_agent_ports_docker_compose(self) -> None: self.check_docker_compose_build( build_dir=build_dir, ) - docker_compose = self.load_and_check_docker_compose_file( path=build_dir / DockerComposeGenerator.output_name ) - assert docker_compose["services"]["abci0"]["ports"] == ["8080:8081"] + assert docker_compose["services"][self.spec.get_abci_container_name(0)][ + "ports" + ] == ["8080:8081"] + assert docker_compose["services"][self.spec.get_tm_container_name(0)][ + "ports" + ] == ["26656:26666"] def test_expose_agent_ports_kubernetes(self) -> None: """Test expose agent ports""" @@ -754,3 +800,71 @@ def test_expose_agent_ports_kubernetes(self) -> None: assert build_config[1]["spec"]["template"]["spec"]["containers"][1][ "ports" ] == [{"containerPort": 8080}] + + +class TestLoadEnvVars(BaseDeployBuildTest): + """Test expose ports from service config.""" + + env_var = "SERVICE_HELLO_WORLD_HELLO_WORLD_STRING" + env_var_path = "SKILL_DUMMY_SKILL_MODELS_PARAMS_ARGS_HELLO_WORLD_MESSAGE" + env_var_value = "ENV_VAR_VALUE" + + def setup(self) -> None: + """Setup test.""" + super().setup() + service_data = get_dummy_service_config(file_number=4) + with open("./service.yaml", "w+") as fp: + yaml.dump_all(service_data, fp) + with OS_ENV_PATCH: + self.spec = ServiceBuilder.from_dir( + self.t / "register_reset", + self.keys_file, + ) + + def _run_test(self) -> None: + """Run test.""" + build_dir = self.t / DEFAULT_BUILD_FOLDER + with mock.patch("os.chown"), OS_ENV_PATCH: + result = self.run_cli( + ( + str(self.keys_file), + "--o", + str(self.t / DEFAULT_BUILD_FOLDER), + ) + ) + + assert result.exit_code == 0, result.output + assert build_dir.exists() + + self.check_docker_compose_build( + build_dir=build_dir, + ) + + docker_compose = self.load_and_check_docker_compose_file( + path=build_dir / DockerComposeGenerator.output_name + ) + + assert ( + f"{self.env_var_path}={self.env_var_value}" + in docker_compose["services"][self.spec.get_abci_container_name(0)][ + "environment" + ] + ) + + def test_load_dot_env(self) -> None: + """Test load `.env` file""" + + (self.t / "register_reset" / DEFAULT_ENV_DOTFILE).write_text( + f"{self.env_var}={self.env_var_value}" + ) + self._run_test() + + def test_load_json(self) -> None: + """Test load `.json` file""" + + env_var_value = "ENV_VAR_VALUE" + env_file = self.t / "register_reset" / "env.json" + env_file.write_text(json.dumps({self.env_var: env_var_value})) + self.cli_options = ("deploy", "--env-file", str(env_file.resolve()), "build") + + self._run_test() diff --git a/tests/test_autonomy/test_cli/test_deploy/test_from_token.py b/tests/test_autonomy/test_cli/test_deploy/test_from_token.py index 4943c20708..fd71286ec9 100644 --- a/tests/test_autonomy/test_cli/test_deploy/test_from_token.py +++ b/tests/test_autonomy/test_cli/test_deploy/test_from_token.py @@ -29,7 +29,6 @@ from aea_test_autonomy.fixture_helpers import registries_scope_class # noqa: F401 from autonomy.chain.exceptions import FailedToRetrieveComponentMetadata -from autonomy.cli.helpers.deployment import BadFunctionCallOutput from tests.conftest import ROOT_DIR, skip_docker_tests from tests.test_autonomy.test_chain.base import BaseChainInteractionTest @@ -117,7 +116,11 @@ def test_from_token( with mock.patch( "autonomy.cli.helpers.deployment.fetch_service_ipfs", return_value=service_dir, - ), run_deployment_patch, build_image_patch, default_remote_registry_patch, default_ipfs_node_patch, ipfs_resolve_patch: + ), ( + run_deployment_patch + ), ( + build_image_patch + ), default_remote_registry_patch, default_ipfs_node_patch, ipfs_resolve_patch: result = self.run_cli( ( str(self.token), @@ -152,7 +155,9 @@ def test_from_token_kubernetes( with mock.patch( "autonomy.cli.helpers.deployment.fetch_service_ipfs", return_value=service_dir, - ), run_deployment_patch as rdp, build_image_patch, default_remote_registry_patch, default_ipfs_node_patch, ipfs_resolve_patch: + ), run_deployment_patch as rdp, ( + build_image_patch + ), default_remote_registry_patch, default_ipfs_node_patch, ipfs_resolve_patch: result = self.run_cli( (str(self.token), str(self.keys_file), "--kubernetes") ) @@ -171,7 +176,13 @@ def test_from_token_kubernetes( def test_fail_on_chain_resolve_connection_error(self) -> None: """Run test.""" - with run_deployment_patch, build_image_patch, default_remote_registry_patch, default_ipfs_node_patch, ipfs_resolve_patch, mock.patch( + with ( + run_deployment_patch + ), ( + build_image_patch + ), ( + default_remote_registry_patch + ), default_ipfs_node_patch, ipfs_resolve_patch, mock.patch( "autonomy.cli.helpers.deployment.resolve_component_id", side_effect=FailedToRetrieveComponentMetadata( "Error connecting RPC endpoint" @@ -190,9 +201,15 @@ def test_fail_on_chain_resolve_connection_error(self) -> None: def test_fail_on_chain_resolve_bad_contract_call(self) -> None: """Run test.""" - with run_deployment_patch, build_image_patch, default_remote_registry_patch, default_ipfs_node_patch, ipfs_resolve_patch, mock.patch( + with ( + run_deployment_patch + ), ( + build_image_patch + ), ( + default_remote_registry_patch + ), default_ipfs_node_patch, ipfs_resolve_patch, mock.patch( "autonomy.cli.helpers.deployment.resolve_component_id", - side_effect=BadFunctionCallOutput, + side_effect=Exception, ): result = self.run_cli( ( diff --git a/tests/test_autonomy/test_cli/test_deploy/test_run_deployment.py b/tests/test_autonomy/test_cli/test_deploy/test_run_deployment.py index b54f6b8260..e1b57e7a66 100644 --- a/tests/test_autonomy/test_cli/test_deploy/test_run_deployment.py +++ b/tests/test_autonomy/test_cli/test_deploy/test_run_deployment.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- # ------------------------------------------------------------------------------ # -# Copyright 2022 Valory AG +# Copyright 2022-2023 Valory AG # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -47,7 +47,7 @@ def test_run( with mock.patch( "autonomy.cli.helpers.deployment.docker_compose.project_from_options" ), mock.patch("autonomy.cli.helpers.deployment.docker_compose.TopLevelCommand"): - result = self.run_cli() + result = self.run_cli(("--detach",)) assert result.exit_code == 0, result.output assert "Running build @" in result.output @@ -58,3 +58,34 @@ def test_missing_config_file( result = self.run_cli() assert result.exit_code == 1, result.output assert "Deployment configuration does not exist" in result.output + + +class TestStop(BaseCliTest): + """Test `stop` command.""" + + cli_options = ("deploy", "stop") + + def setup(self) -> None: + """Setup test method.""" + super().setup() + os.chdir(self.t) + + def test_run( + self, + ) -> None: + """Run test.""" + (self.t / DOCKER_COMPOSE_YAML).touch() + with mock.patch( + "autonomy.cli.helpers.deployment.docker_compose.project_from_options" + ), mock.patch("autonomy.cli.helpers.deployment.docker_compose.TopLevelCommand"): + result = self.run_cli() + assert result.exit_code == 0, result.output + assert "Don't cancel while stopping services..." in result.output + + def test_missing_config_file( + self, + ) -> None: + """Run test.""" + result = self.run_cli() + assert result.exit_code == 1, result.output + assert "Deployment configuration does not exist" in result.output diff --git a/tests/test_autonomy/test_cli/test_fetch.py b/tests/test_autonomy/test_cli/test_fetch.py index 30186c9b38..b211daf7b1 100644 --- a/tests/test_autonomy/test_cli/test_fetch.py +++ b/tests/test_autonomy/test_cli/test_fetch.py @@ -163,6 +163,21 @@ def test_publish_and_fetch_service_ipfs(self) -> None: assert result.exit_code == 0, result.output assert service_dir.exists() + alias = "some_service" + + with mock.patch( + "autonomy.cli.helpers.registry.get_default_remote_registry", + new=lambda: "ipfs", + ), mock.patch( + "autonomy.cli.helpers.registry.get_ipfs_node_multiaddr", + new=lambda: IPFS_REGISTRY, + ), cd( + service_dir.parent + ): + result = self.run_cli(("--remote", "--alias", alias, expected_hash)) + assert result.exit_code == 0, result.output + assert (service_dir.parent / alias).exists() + shutil.rmtree(service_dir) def test_fetch_service_mixed( diff --git a/tests/test_autonomy/test_cli/test_helpers/test_chain_helpers.py b/tests/test_autonomy/test_cli/test_helpers/test_chain_helpers.py index eb7ea9f04c..1bfa40c662 100644 --- a/tests/test_autonomy/test_cli/test_helpers/test_chain_helpers.py +++ b/tests/test_autonomy/test_cli/test_helpers/test_chain_helpers.py @@ -19,31 +19,23 @@ """Test chain helpers.""" -from typing import Dict +import re +import tempfile +from pathlib import Path from unittest import mock import click import pytest -from aea.configurations.data_types import PackageId, PackageType, PublicId -from aea_ledger_ethereum_hwi.hwi import EthereumHWIApi, EthereumHWICrypto +from aea.configurations.data_types import PackageType from aea_test_autonomy.configurations import ETHEREUM_KEY_DEPLOYER -from gql import Client as GQLClient from autonomy.chain.base import ServiceState from autonomy.chain.config import ChainConfigs, ChainType -from autonomy.chain.mint import registry_contracts -from autonomy.cli.helpers.chain import ( - activate_service, - deploy_service, - get_ledger_and_crypto_objects, - get_on_chain_dependencies, - mint_component, - mint_service, - register_instance, -) +from autonomy.chain.exceptions import FailedToRetrieveComponentMetadata +from autonomy.chain.mint import DEFAULT_NFT_IMAGE_HASH, registry_contracts +from autonomy.cli.helpers.chain import MintHelper, OnChainHelper, ServiceHelper from tests.conftest import ROOT_DIR -from tests.test_autonomy.test_cli.test_mint.test_mint_components import DummyContract PACKAGE_DIR = ROOT_DIR / "packages" / "valory" / "protocols" / "abci" @@ -64,6 +56,14 @@ _ = registry_contracts.service_manager +def _get_ledger_and_crypto_objects_patch() -> mock._patch: + return mock.patch.object( + OnChainHelper, + "get_ledger_and_crypto_objects", + return_value=(mock.MagicMock(), mock.MagicMock()), + ) + + class TestMintComponentMethod: """Test `mint_component` method.""" @@ -74,44 +74,22 @@ def test_mint_component_rpc_connect_fail( with pytest.raises( click.ClickException, - match="Component mint failed with following error; Cannot connect to the given RPC", + match=re.escape( + "Component mint failed with following error; RPCError(Cannot connect to the given RPC)" + ), ): with publish_metadata_patch, mock.patch( "autonomy.chain.mint.Crypto.sign_transaction" ): - mint_component( - package_path=PACKAGE_DIR, - package_type=PackageType.PROTOCOL, - key=ETHEREUM_KEY_DEPLOYER, + MintHelper( chain_type=ChainType.LOCAL, - ) - - def test_mint_component_token_id_retrieve_fail( - self, - ) -> None: - """Test token ID retrieval failure method.""" - with pytest.raises( - click.ClickException, - match=( - "Component mint was successful but token ID retrieving failed with following error; " - "Connection interrupted while waiting for the unitId emit event" - ), - ): - with publish_metadata_patch, mock.patch.object( - registry_contracts, "_component_registry", DummyContract() - ), mock.patch.object( - registry_contracts, "_registries_manager", DummyContract() - ), mock.patch( - "autonomy.chain.mint.transact" - ), mock.patch( - "autonomy.cli.helpers.chain.EthereumApi.try_get_gas_pricing" - ): - mint_component( + key=ETHEREUM_KEY_DEPLOYER, + ).load_package_configuration( package_path=PACKAGE_DIR, package_type=PackageType.PROTOCOL, - key=ETHEREUM_KEY_DEPLOYER, - chain_type=ChainType.LOCAL, - ) + ).verify_nft().verify_component_dependencies( + dependencies=(), # type: ignore + ).publish_metadata().mint_component() def test_rpc_cannot_be_none( self, @@ -126,12 +104,15 @@ def test_rpc_cannot_be_none( "using `GOERLI_CHAIN_RPC` environment variable" ), ): - mint_component( + MintHelper( + chain_type=ChainType.GOERLI, + key=ETHEREUM_KEY_DEPLOYER, + ).load_package_configuration( package_path=PACKAGE_DIR, package_type=PackageType.PROTOCOL, - key=ETHEREUM_KEY_DEPLOYER, - chain_type=ChainType.GOERLI, - ) + ).verify_nft().verify_component_dependencies( + dependencies=(), # type: ignore + ).publish_metadata().mint_component() def test_missing_nft_hash( self, @@ -146,185 +127,200 @@ def test_missing_nft_hash( "autonomy.cli.helpers.chain.ChainConfigs.get", return_value=ChainConfigs.local, ): - mint_component( + MintHelper( + chain_type=ChainType.GOERLI, + key=ETHEREUM_KEY_DEPLOYER, + ).load_package_configuration( package_path=PACKAGE_DIR, package_type=PackageType.PROTOCOL, - key=ETHEREUM_KEY_DEPLOYER, - chain_type=ChainType.GOERLI, - ) + ).verify_nft().verify_component_dependencies( + dependencies=(), # type: ignore + ).publish_metadata().mint_component() - def test_mint_component_timeout( - self, - ) -> None: - """Test timeout error.""" - with pytest.raises( +class TestRequiredEnvVars: + """Test required env var check works.""" + + _component_failure = ( + "Addresses for following contracts are None, please set them using their respective environment variables\n" + "- Set `registries_manager` address using `CUSTOM_REGISTRIES_MANAGER_ADDRESS`\n" + "- Set `component_registry` address using `CUSTOM_COMPONENT_REGISTRY_ADDRESS`" + ) + + _service_failure = ( + "Addresses for following contracts are None, please set them using their respective environment variables\n" + "- Set `service_manager` address using `CUSTOM_SERVICE_MANAGER_ADDRESS`\n" + "- Set `service_registry` address using `CUSTOM_SERVICE_REGISTRY_ADDRESS`" + ) + + def test_component_mint(self) -> None: + """Test component mint env vars.""" + with _get_ledger_and_crypto_objects_patch(), pytest.raises( click.ClickException, - match=( - "Component mint was successful but token ID retrieving failed with following error; " - "Could not retrieve the token in given time limit." - ), + match=self._component_failure, ): - with mock.patch( - "autonomy.cli.helpers.chain.get_on_chain_dependencies", return_value=[] - ), mock.patch( - "autonomy.cli.helpers.chain.publish_metadata", - return_value=(None, None), - ), mock.patch( - "autonomy.chain.mint.transact" - ), mock.patch.object( - registry_contracts._registries_manager, - "get_create_transaction", - return_value=False, - ), mock.patch.object( - registry_contracts._component_registry, - "filter_token_id_from_emitted_events", - return_value=None, - ): - mint_component( - package_path=PACKAGE_DIR, - package_type=PackageType.PROTOCOL, - key=ETHEREUM_KEY_DEPLOYER, - chain_type=ChainType.LOCAL, - timeout=1.0, - ) + mint_helper = MintHelper( + chain_type=ChainType.CUSTOM, + key=ETHEREUM_KEY_DEPLOYER, + ) + mint_helper.mint_component() + def test_component_update(self) -> None: + """Test component update env vars.""" + with _get_ledger_and_crypto_objects_patch(), pytest.raises( + click.ClickException, + match=self._component_failure, + ): + mint_helper = MintHelper( + chain_type=ChainType.CUSTOM, + key=ETHEREUM_KEY_DEPLOYER, + ) + mint_helper.update_component() -def test_mint_service_timeout() -> None: - """Test timeout error.""" + def test_servic_mint(self) -> None: + """Test component update env vars.""" + with _get_ledger_and_crypto_objects_patch(), pytest.raises( + click.ClickException, + match=self._service_failure, + ): + mint_helper = MintHelper( + chain_type=ChainType.CUSTOM, + key=ETHEREUM_KEY_DEPLOYER, + ) + mint_helper.mint_service(1, 1, 1) - with pytest.raises( - click.ClickException, - match=( - "Service mint was successful but token ID retrieving failed with following error; " - "Could not retrieve the token in given time limit" - ), - ): - with mock.patch( - "autonomy.cli.helpers.chain.get_on_chain_dependencies", - return_value=[1], - ), mock.patch( - "autonomy.cli.helpers.chain.load_configuration_object" - ), mock.patch( - "autonomy.cli.helpers.chain.publish_metadata", - return_value=(None, None), - ), mock.patch( - "autonomy.chain.mint.transact" - ), mock.patch.object( - registry_contracts._service_manager, - "get_create_transaction", - return_value=False, - ), mock.patch.object( - registry_contracts._service_registry, - "filter_token_id_from_emitted_events", - return_value=None, + def test_service_update(self) -> None: + """Test component update env vars.""" + with _get_ledger_and_crypto_objects_patch(), pytest.raises( + click.ClickException, + match=self._service_failure, ): - mint_service( - package_path=PACKAGE_DIR, + mint_helper = MintHelper( + chain_type=ChainType.CUSTOM, key=ETHEREUM_KEY_DEPLOYER, - chain_type=ChainType.LOCAL, - agent_id=1, - number_of_slots=4, - cost_of_bond=1, - threshold=3, - timeout=1.0, ) + mint_helper.update_service(1, 1, 1) + def test_activate_service(self) -> None: + """Test component update env vars.""" + with _get_ledger_and_crypto_objects_patch(), pytest.raises( + click.ClickException, + match=self._service_failure, + ): + mint_helper = ServiceHelper( + service_id=1, + chain_type=ChainType.CUSTOM, + key=ETHEREUM_KEY_DEPLOYER, + ) + mint_helper.check_is_service_token_secured().activate_service() -def test_activate_service_timeout_failure() -> None: - """Test `activate_service` method""" + def test_register_instances(self) -> None: + """Test component update env vars.""" + with _get_ledger_and_crypto_objects_patch(), pytest.raises( + click.ClickException, + match=self._service_failure, + ): + mint_helper = ServiceHelper( + service_id=1, + chain_type=ChainType.CUSTOM, + key=ETHEREUM_KEY_DEPLOYER, + ) + mint_helper.check_is_service_token_secured().register_instance(["0x"], [1]) - with pytest.raises( - click.ClickException, - match="Could not verify the service activation in given time", - ): - with mock.patch.object( - registry_contracts._service_registry, - "verify_service_has_been_activated", - return_value=False, - ), mock.patch.object( - registry_contracts._service_manager, - "get_activate_registration_transaction", - return_value=False, - ), mock.patch( - "autonomy.chain.service.transact" - ), mock.patch( - "autonomy.chain.service.get_service_info", - return_value=(1, None, ServiceState.PRE_REGISTRATION.value, None), + def test_deploy_instances(self) -> None: + """Test component update env vars.""" + with _get_ledger_and_crypto_objects_patch(), pytest.raises( + click.ClickException, + match=( + "Addresses for following contracts are None, please set them using their respective environment variables\n" + "- Set `service_manager` address using `CUSTOM_SERVICE_MANAGER_ADDRESS`\n" + "- Set `service_registry` address using `CUSTOM_SERVICE_REGISTRY_ADDRESS`\n" + "- Set `gnosis_safe_proxy_factory` address using `CUSTOM_GNOSIS_SAFE_PROXY_FACTORY_ADDRESS`\n" + "- Set `gnosis_safe_same_address_multisig` address using `CUSTOM_GNOSIS_SAFE_SAME_ADDRESS_MULTISIG_ADDRESS`" + ), ): - activate_service( - service_id=0, + mint_helper = ServiceHelper( + service_id=1, + chain_type=ChainType.CUSTOM, + key=ETHEREUM_KEY_DEPLOYER, + ) + mint_helper.check_is_service_token_secured().deploy_service() + + def test_unbond(self) -> None: + """Test component update env vars.""" + with _get_ledger_and_crypto_objects_patch(), pytest.raises( + click.ClickException, + match=self._service_failure, + ): + mint_helper = ServiceHelper( + service_id=1, + chain_type=ChainType.CUSTOM, key=ETHEREUM_KEY_DEPLOYER, - chain_type=ChainType.LOCAL, - timeout=1.0, ) + mint_helper.check_is_service_token_secured().unbond_service() -def test_register_instance_timeout_failure() -> None: - """Test `deploy_service` method""" +@pytest.mark.parametrize( + argnames=("state", "error"), + argvalues=( + (ServiceState.NON_EXISTENT, "Service does not exist"), + (ServiceState.PRE_REGISTRATION, "Service not active"), + (ServiceState.TERMINATED_BONDED, "Service already terminated"), + ), +) +def test_terminate_service_failures(state: ServiceState, error: str) -> None: + """Test `terminate_service` method""" with pytest.raises( click.ClickException, - match="Could not verify the instance registration for {'0x'} in given time", + match=error, ): - with mock.patch.object( - registry_contracts._service_registry, - "verify_agent_instance_registration", - return_value=[], - ), mock.patch.object( - registry_contracts._service_manager, - "get_register_instance_transaction", - return_value=False, - ), mock.patch( - "autonomy.chain.service.transact" - ), mock.patch( + with mock.patch( "autonomy.chain.service.get_service_info", - return_value=(1, None, ServiceState.ACTIVE_REGISTRATION.value, None), + return_value=(1, None, state.value, None), ): - register_instance( + ServiceHelper( service_id=0, - instances=["0x"], - agent_ids=[1], key=ETHEREUM_KEY_DEPLOYER, chain_type=ChainType.LOCAL, - timeout=1.0, - ) + ).terminate_service() -def test_deploy_service_timeout_failure() -> None: - """Test `deploy_service` method""" +@pytest.mark.parametrize( + argnames=("state", "error"), + argvalues=( + (ServiceState.NON_EXISTENT, "Service does not exist"), + ( + ServiceState.PRE_REGISTRATION, + "Service needs to be in terminated-bonded state", + ), + ), +) +def test_unbond_service_failures(state: ServiceState, error: str) -> None: + """Test `terminate_service` method""" with pytest.raises( click.ClickException, - match="Could not verify the service deployment for service 0 in given time", + match=error, ): - with mock.patch.object( - registry_contracts._service_registry, - "verify_service_has_been_deployed", - return_value=False, - ), mock.patch.object( - registry_contracts._service_manager, - "get_service_deploy_transaction", - return_value=False, - ), mock.patch( - "autonomy.chain.service.transact" - ), mock.patch( + with mock.patch( "autonomy.chain.service.get_service_info", - return_value=(1, None, ServiceState.FINISHED_REGISTRATION.value, None), + return_value=(1, None, state.value, None), ): - deploy_service( + ServiceHelper( service_id=0, key=ETHEREUM_KEY_DEPLOYER, chain_type=ChainType.LOCAL, - timeout=1.0, - ) + ).unbond_service() +@pytest.mark.skip(reason="https://github.com/valory-xyz/open-aea/issues/671") def test_get_ledger_and_crypto_objects() -> None: """Test `get_ledger_and_crypto_objects` for hardware wallet support""" + from aea_ledger_ethereum_hwi.hwi import EthereumHWIApi, EthereumHWICrypto with mock.patch.object(EthereumHWICrypto, "entity"): - ledger_api, crypto = get_ledger_and_crypto_objects( + ledger_api, crypto = OnChainHelper.get_ledger_and_crypto_objects( chain_type=ChainType.LOCAL, hwi=True, ) @@ -340,108 +336,115 @@ def test_get_ledger_and_crypto_failure() -> None: click.ClickException, match="Please provide key path using `--key` or use `--hwi` if you want to use a hardware wallet", ): - mint_component( + MintHelper( + chain_type=ChainType.GOERLI, + ).load_package_configuration( package_path=PACKAGE_DIR, package_type=PackageType.PROTOCOL, - key=None, - chain_type=ChainType.LOCAL, - ) + ).verify_nft().verify_component_dependencies( + dependencies=(), # type: ignore + ).publish_metadata().mint_component() -class TestGetOnChainDependencies: - """Test `get_on_chain_dependencies` method.""" +def test_verify_component_dependencies_failures() -> None: + """Test `verify_component_dependencies` failures""" - dependencies = { - PackageId( - PackageType.PROTOCOL, - PublicId( - author="author", - name="package", - package_hash="bafybei0000000000000000000000000000000000000000000000000000", - ), - ) - } - - @staticmethod - def mock_client(return_value: Dict) -> mock._patch: - """Mock GQL Client.""" - return mock.patch.object( - GQLClient, - "execute", - return_value=return_value, + with pytest.raises( + click.ClickException, + match=("Dependency verification failed"), + ), mock.patch.object( + MintHelper, + "get_ledger_and_crypto_objects", + return_value=(mock.MagicMock(), mock.MagicMock()), + ), mock.patch( + "autonomy.cli.helpers.chain.verify_component_dependencies", + side_effect=FailedToRetrieveComponentMetadata, + ): + MintHelper( + key=ETHEREUM_KEY_DEPLOYER, + chain_type=ChainType.ETHEREUM, + ).load_package_configuration( + package_path=PACKAGE_DIR, + package_type=PackageType.PROTOCOL, + ).verify_nft( + nft=DEFAULT_NFT_IMAGE_HASH, + ).verify_component_dependencies( + dependencies=(1,), # type: ignore ) - def test_get_on_chain_dependencies(self) -> None: - """Test `get_on_chain_dependencies` method""" - - with self.mock_client( - return_value={ - "units": [{"tokenId": 0}], - } - ): - dependencies = get_on_chain_dependencies( - dependencies=self.dependencies, - ) - assert dependencies == [0] +def test_verify_service_dependencies_failures() -> None: + """Test `verify_service_dependencies` failures""" - def test_get_on_chain_dependencies_multiple_deps(self) -> None: - """Test `get_on_chain_dependencies` method""" - - with self.mock_client( - return_value={ - "units": [{"tokenId": 0}, {"tokenId": 1}], - }, - ), mock.patch("click.prompt", return_value=1): - dependencies = get_on_chain_dependencies( - dependencies=self.dependencies, - ) + with pytest.raises( + click.ClickException, + match=("Dependency verification failed"), + ), mock.patch.object( + MintHelper, + "get_ledger_and_crypto_objects", + return_value=(mock.MagicMock(), mock.MagicMock()), + ), mock.patch( + "autonomy.cli.helpers.chain.verify_service_dependencies", + side_effect=FailedToRetrieveComponentMetadata, + ): + MintHelper( + key=ETHEREUM_KEY_DEPLOYER, + chain_type=ChainType.ETHEREUM, + ).load_package_configuration( + package_path=PACKAGE_DIR, + package_type=PackageType.PROTOCOL, + ).verify_nft( + nft=DEFAULT_NFT_IMAGE_HASH, + ).verify_service_dependencies( + agent_id=1 + ) - assert dependencies == [1] - def test_get_on_chain_dependencies_multiple_deps_use_latest(self) -> None: - """Test `get_on_chain_dependencies` method""" +def test_token_secure_check_on_custom_chain() -> None: + """Test token_secure is False on custom chain.""" - with self.mock_client( - return_value={ - "units": [{"tokenId": 0}, {"tokenId": 1}], - }, - ): - dependencies = get_on_chain_dependencies( - dependencies=self.dependencies, - use_latest_dependencies=True, - ) - - assert dependencies == [1] + with _get_ledger_and_crypto_objects_patch(): + service_helper = ServiceHelper( + service_id=1, chain_type=ChainType.CUSTOM, key=ETHEREUM_KEY_DEPLOYER + ) + assert service_helper.check_is_service_token_secured().token_secured is False - def test_skip_hash(self) -> None: - """Test `get_on_chain_dependencies` method""" - with self.mock_client( - return_value={ - "units": [{"tokenId": 0}, {"tokenId": 1}], - }, - ): - dependencies = get_on_chain_dependencies( - dependencies=self.dependencies, - use_latest_dependencies=True, - skip_hash_check=True, - ) +def test_mint_with_token_on_custom_chain() -> None: + """Test minting with token on L2 chains fail.""" - assert dependencies == [1] + with _get_ledger_and_crypto_objects_patch(), pytest.raises( + click.ClickException, match="Cannot use custom token for bonding on L2 chains" + ): + MintHelper( # nosec + chain_type=ChainType.CUSTOM, key=ETHEREUM_KEY_DEPLOYER + ).mint_service( + number_of_slots=1, + cost_of_bond=1, + threshold=1, + token="0x", + ) - def test_get_on_chain_dependencies_failure(self) -> None: - """Test `get_on_chain_dependencies` method""" - with pytest.raises( - click.ClickException, - match="No on chain registration found for following dependencies", - ), self.mock_client( - return_value={ - "units": [], - }, - ): - get_on_chain_dependencies( - dependencies=self.dependencies, - use_latest_dependencies=True, - ) +@pytest.mark.parametrize( + argnames="key", + argvalues=( + "0xdf57089febbacf7ba0bc227dafbffa9fc08a93fdc68e1e42411a14efcf23656e\n", + "df57089febbacf7ba0bc227dafbffa9fc08a93fdc68e1e42411a14efcf23656", + "0x9fe46736679d2d9a65f0992f2272de9f3c7fa6e0", + ), +) +def test_wrong_private_key_format(key: str) -> None: + """Test an error is raised if the private key format is wrong.""" + with tempfile.TemporaryDirectory() as temp_dir, pytest.raises( + click.ClickException, + match=( + "Cannot load private key for following possible reasons\n" + "- Wrong key format\n" + "- Wrong key length\n" + "- Trailing spaces or new line characters" + ), + ): + file = Path(temp_dir, "key.txt") + file.write_text(key) + OnChainHelper.load_crypto(file=file) diff --git a/tests/test_autonomy/test_cli/test_helpers/test_env_helpers.py b/tests/test_autonomy/test_cli/test_helpers/test_env_helpers.py new file mode 100644 index 0000000000..ec204ff10c --- /dev/null +++ b/tests/test_autonomy/test_cli/test_helpers/test_env_helpers.py @@ -0,0 +1,91 @@ +# -*- coding: utf-8 -*- +# ------------------------------------------------------------------------------ +# +# Copyright 2023 Valory AG +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# ------------------------------------------------------------------------------ + +"""The module contains test_helpers for module tests.""" + +import json +import os +import random +import string +import tempfile +from pathlib import Path +from unittest import mock + +from aea.configurations.constants import DEFAULT_ENV_DOTFILE + +from autonomy.cli.helpers.env import load_env_file + + +class TestLoadEnvFile: + """Test `load_env_file` file.""" + + _t: tempfile.TemporaryDirectory + t: Path + cwd: Path + + env_var = "ENV_VAR" + + @staticmethod + def generate_random_value(n: int = 6) -> str: + """Generate random string.""" + return "".join([random.choice(string.ascii_letters) for i in range(n)]) # nosec + + def setup(self) -> None: + """Setup test""" + + self._t = tempfile.TemporaryDirectory() + self.t = Path(self._t.name) + self.cwd = Path.cwd() + + os.chdir(self.t) + + def test_load_dot_env(self) -> None: + """Test `.env` file.""" + env_var_value = self.generate_random_value() + dotenv_file = self.t / DEFAULT_ENV_DOTFILE + dotenv_file.write_text(f"{self.env_var}={env_var_value}") + with mock.patch.dict(os.environ): + load_env_file(file=dotenv_file) + assert os.environ[self.env_var] == env_var_value + + def test_load_json(self) -> None: + """Test `.json` file.""" + + env_var_value = self.generate_random_value() + json_file = self.t / "env.json" + json_file.write_text(json.dumps({self.env_var: env_var_value})) + with mock.patch.dict(os.environ): + load_env_file(file=json_file) + assert os.environ[self.env_var] == env_var_value + + def test_load_json_serialize(self) -> None: + """Test `.json` file with serialize values.""" + + env_var_value = [self.generate_random_value(), self.generate_random_value()] + json_file = self.t / "env.json" + json_file.write_text(json.dumps({self.env_var: env_var_value})) + + with mock.patch.dict(os.environ): + load_env_file(file=json_file, serialize_json=True) + assert json.loads(os.environ[self.env_var]) == env_var_value + + def teardown(self) -> None: + """Test teardown""" + os.chdir(self.cwd) + self._t.cleanup() diff --git a/tests/test_autonomy/test_cli/test_helpers/test_fsm_spec.py b/tests/test_autonomy/test_cli/test_helpers/test_fsm_spec.py index 5823971ed8..633f40cdd0 100644 --- a/tests/test_autonomy/test_cli/test_helpers/test_fsm_spec.py +++ b/tests/test_autonomy/test_cli/test_helpers/test_fsm_spec.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- # ------------------------------------------------------------------------------ # -# Copyright 2022 Valory AG +# Copyright 2022-2023 Valory AG # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -39,7 +39,7 @@ ) import packages -from packages.valory.skills import hello_world_abci, test_abci +from packages.valory.skills import offend_abci, test_abci from tests.conftest import ROOT_DIR @@ -72,7 +72,7 @@ def test_import_and_validate_app_class_raises() -> None: def test_update_one() -> None: """Test update_one""" - package_path = Path(hello_world_abci.__file__).parent.relative_to(ROOT_DIR) + package_path = Path(offend_abci.__file__).parent.relative_to(ROOT_DIR) with mock.patch.object(FSMSpecificationLoader, "dump") as m: update_one(package_path) m.assert_called_once() @@ -86,7 +86,7 @@ def test_update_one_raises() -> None: with pytest.raises(ClickException, match=expected): update_one(package_path) - package_path = Path(hello_world_abci.__file__).parent.relative_to(ROOT_DIR) + package_path = Path(offend_abci.__file__).parent.relative_to(ROOT_DIR) expected = "Please provide name for the app class or make sure FSM specification file is properly defined." with mock.patch.object(FSMSpecificationLoader, "load", return_value={}): with pytest.raises(ValueError, match=expected): @@ -96,27 +96,27 @@ def test_update_one_raises() -> None: def test_check_one() -> None: """Test check_one""" - package_path = Path(hello_world_abci.__file__).parent.relative_to(ROOT_DIR) + package_path = Path(offend_abci.__file__).parent.relative_to(ROOT_DIR) check_one(package_path) def test_check_one_raises() -> None: """Test check_one raises""" - package_path = Path(hello_world_abci.__file__).parent.relative_to(ROOT_DIR) + package_path = Path(offend_abci.__file__).parent.relative_to(ROOT_DIR) expected = "Please provide name for the app class or make sure FSM specification file is properly defined." with mock.patch.object(FSMSpecificationLoader, "load", return_value={}): with pytest.raises(ValueError, match=expected): update_one(package_path) - expected = 'Class .* is not in "packages.valory.skills.hello_world_abci.rounds"' + expected = 'Class .* is not in "packages.valory.skills.offend_abci.rounds"' with pytest.raises(ClickException, match=expected): check_one(package_path, app_class="DummyAbciApp") target = "autonomy.cli.helpers.fsm_spec.check_unreferenced_events" with mock.patch(target, return_value=["Event.WIN_LOTTERY"]): - expected = "Event reference check failed with .*" + expected = "Unreferenced events found in `OffendAbciApp`\n- Event.WIN_LOTTERY" with pytest.raises(DFASpecificationError, match=expected): check_one(package_path) diff --git a/tests/test_autonomy/test_cli/test_mint/test_mint_components.py b/tests/test_autonomy/test_cli/test_mint/test_mint_components.py index 16b54ecf16..5665df2dbb 100644 --- a/tests/test_autonomy/test_cli/test_mint/test_mint_components.py +++ b/tests/test_autonomy/test_cli/test_mint/test_mint_components.py @@ -19,7 +19,7 @@ """Test `mint` command group.""" -from typing import Any +from typing import Any, Tuple from unittest import mock import pytest @@ -28,8 +28,8 @@ from aea_test_autonomy.fixture_helpers import registries_scope_class # noqa: F401 from requests.exceptions import ConnectionError as RequestsConnectionError +from autonomy.chain.config import ChainConfigs from autonomy.chain.mint import registry_contracts -from autonomy.chain.subgraph.client import SubgraphClient from tests.test_autonomy.test_chain.base import ( BaseChainInteractionTest, @@ -42,6 +42,7 @@ DUMMY_SERVICE, DUMMY_SKILL, ) +from tests.test_autonomy.test_cli.base import BaseCliTest CUSTOM_OWNER = "0x8626F6940E2EB28930EFB4CEF49B2D1F2C9C1199" @@ -50,11 +51,9 @@ class DummyContract: """Dummy contract""" - def filter_token_id_from_emitted_events(self, *args: Any, **kwargs: Any) -> None: + def get_create_events(self, *args: Any, **kwargs: Any) -> None: """Dummy method implementation""" - raise RequestsConnectionError() - def get_create_transaction(self, *args: Any, **kwargs: Any) -> None: """Dummy method implementation""" @@ -88,26 +87,52 @@ def test_mint_components(self, package_id: PackageId) -> None: str(ETHEREUM_KEY_DEPLOYER), ] - dependencies = [] + if package_id.package_type == PackageType.CONNECTION: + # Dummy protocol is a dependency for the dummy connection + commands += ["-d", str(self.mint_component(package_id=DUMMY_PROTOCOL))] + + if package_id.package_type == PackageType.SKILL: + # Dummy protocol, dummy contract and dummy connection are dependencies for the dummy skill + commands += [ + "-d", + str(self.mint_component(package_id=DUMMY_PROTOCOL)), + "-d", + str(self.mint_component(package_id=DUMMY_CONTRACT)), + "-d", + str(self.mint_component(package_id=DUMMY_CONNECTION)), + ] + if package_id.package_type == PackageType.AGENT: - dependencies.append(self.mint_component(package_id=DUMMY_PROTOCOL)) + # Dummy protocol, dummy contract, dummy connection and dummy skill are dependencies for the dummy skill + commands += [ + "-d", + str(self.mint_component(package_id=DUMMY_PROTOCOL)), + "-d", + str(self.mint_component(package_id=DUMMY_CONTRACT)), + "-d", + str(self.mint_component(package_id=DUMMY_CONNECTION)), + "-d", + str(self.mint_component(package_id=DUMMY_SKILL)), + ] - with mock.patch( - "autonomy.cli.helpers.chain.get_on_chain_dependencies", - return_value=dependencies, - ): - result = self.run_cli(commands=tuple(commands)) + result = self.run_cli(commands=tuple(commands)) - assert result.exit_code == 0, result.output + assert result.exit_code == 0, result.stderr assert "Component minted with:" in result.output assert "Metadata Hash:" in result.output assert "Token ID:" in result.output - token_id = self.extract_token_id_from_output(output=result.output) self.verify_minted_token_id( token_id=token_id, package_id=package_id, ) + + commands += ["--update", str(token_id)] + result = self.run_cli(commands=tuple(commands)) + + assert result.exit_code == 0, result.stderr + assert "Component hash updated:" in result.output + assert f"Token ID: {token_id}" in result.output self.verify_and_remove_metadata_file(token_id=token_id) def test_mint_component_with_owner( @@ -146,9 +171,10 @@ def test_mint_service( self, ) -> None: """Test mint components.""" + with mock.patch("autonomy.cli.helpers.chain.verify_component_dependencies"): + agent_id = self.mint_component(package_id=DUMMY_AGENT, dependencies=[1]) - agent_id = 1 - commands = ( + commands = [ DUMMY_SERVICE.package_type.value, str( DUMMY_PACKAGE_MANAGER.package_path_from_package_id( @@ -160,15 +186,50 @@ def test_mint_service( "-a", str(agent_id), *DEFAULT_SERVICE_MINT_PARAMETERS[2:], + ] + + result = self.run_cli(commands=tuple(commands)) + + assert result.exit_code == 0, result + assert "Service minted with:" in result.output + assert "Metadata Hash:" in result.output + assert "Token ID:" in result.output + + token_id = self.extract_token_id_from_output(output=result.output) + self.verify_minted_token_id( + token_id=token_id, + package_id=DUMMY_SERVICE, ) - with mock.patch( - "autonomy.cli.helpers.chain.get_on_chain_dependencies", - return_value=[ - agent_id, - ], - ): - result = self.run_cli(commands=commands) + commands += ["--update", str(token_id)] + result = self.run_cli(commands=tuple(commands)) + assert result.exit_code == 0, result.stderr + assert "Service updated with:" in result.output + assert f"Token ID: {token_id}" in result.output + self.verify_and_remove_metadata_file(token_id=token_id) + + def test_update_service_failure( + self, + ) -> None: + """Test mint components.""" + with mock.patch("autonomy.cli.helpers.chain.verify_component_dependencies"): + agent_id = self.mint_component(package_id=DUMMY_AGENT, dependencies=[1]) + + commands = [ + DUMMY_SERVICE.package_type.value, + str( + DUMMY_PACKAGE_MANAGER.package_path_from_package_id( + package_id=DUMMY_SERVICE + ) + ), + "--key", + str(ETHEREUM_KEY_DEPLOYER), + "-a", + str(agent_id), + *DEFAULT_SERVICE_MINT_PARAMETERS[2:], + ] + + result = self.run_cli(commands=tuple(commands)) assert result.exit_code == 0, result assert "Service minted with:" in result.output @@ -180,14 +241,24 @@ def test_mint_service( token_id=token_id, package_id=DUMMY_SERVICE, ) + self.service_manager.activate(service_id=token_id) + + commands += ["--update", str(token_id)] + result = self.run_cli(commands=tuple(commands)) + assert result.exit_code == 1, result.stdout + assert ( + "Cannot update service hash, service needs to be in the pre-registration state" + in result.stderr + ) self.verify_and_remove_metadata_file(token_id=token_id) def test_mint_service_with_owner( self, ) -> None: """Test mint components.""" + with mock.patch("autonomy.cli.helpers.chain.verify_component_dependencies"): + agent_id = self.mint_component(package_id=DUMMY_AGENT, dependencies=[1]) - agent_id = 1 commands = ( DUMMY_SERVICE.package_type.value, str( @@ -203,13 +274,8 @@ def test_mint_service_with_owner( "--owner", CUSTOM_OWNER, ) - with mock.patch( - "autonomy.cli.helpers.chain.get_on_chain_dependencies", - return_value=[ - agent_id, - ], - ): - result = self.run_cli(commands=commands) + + result = self.run_cli(commands=commands) assert result.exit_code == 0, result assert "Service minted with:" in result.output @@ -224,61 +290,93 @@ def test_mint_service_with_owner( ) self.verify_and_remove_metadata_file(token_id=token_id) - def test_connection_error( - self, + @pytest.mark.parametrize( + argnames=("package_id", "parameters"), + argvalues=( + (DUMMY_CONNECTION, ("-d", "2")), + (DUMMY_AGENT, ("-d", "1")), + (DUMMY_SERVICE, ("-a", "1", "-n", "4", "-c", "1000", "--threshold", "3")), + ), + ) + def test_metadata_retrive_failure( + self, package_id: PackageId, parameters: Tuple[str, ...] ) -> None: """Test connection error.""" - with mock.patch( - "autonomy.chain.mint.transact", side_effect=RequestsConnectionError + _ = registry_contracts.component_registry + _ = registry_contracts.agent_registry + _ = registry_contracts.service_registry + + with mock.patch.object( + registry_contracts._component_registry, + "get_token_uri", + side_effect=RequestsConnectionError, + ), mock.patch.object( + registry_contracts._agent_registry, + "get_token_uri", + side_effect=RequestsConnectionError, + ), mock.patch.object( + registry_contracts._service_registry, + "get_token_uri", + side_effect=RequestsConnectionError, + ), mock.patch.object( + ChainConfigs, "get", return_value=ChainConfigs.local ): result = self.run_cli( commands=( - "protocol", + "--use-ethereum", + package_id.package_type.value, str( DUMMY_PACKAGE_MANAGER.package_path_from_package_id( - package_id=DUMMY_PROTOCOL + package_id=package_id ) ), "--key", str(ETHEREUM_KEY_DEPLOYER), + "--nft", + "Qmbh9SQLbNRawh9Km3PMEDSxo77k1wib8fYZUdZkhPBiev", + *parameters, ), ) self.cli_runner.mix_stderr = True assert result.exit_code == 1, result.output assert ( - "Component mint failed with following error; Cannot connect to the given RPC" + "Dependency verification failed; Error connecting to the RPC" in result.stderr ) - def test_connection_error_service( - self, - ) -> None: - """Test connection error.""" - - with mock.patch( - "autonomy.chain.mint.transact", side_effect=RequestsConnectionError + with mock.patch.object( + registry_contracts._component_registry, "get_token_uri" + ), mock.patch.object( + registry_contracts._agent_registry, "get_token_uri" + ), mock.patch.object( + registry_contracts._service_registry, "get_token_uri" ), mock.patch( - "autonomy.cli.helpers.chain.get_on_chain_dependencies", return_value=[1] + "autonomy.chain.utils.r_get", side_effect=RequestsConnectionError + ), mock.patch.object( + ChainConfigs, "get", return_value=ChainConfigs.local ): result = self.run_cli( commands=( - "service", + "--use-ethereum", + package_id.package_type.value, str( DUMMY_PACKAGE_MANAGER.package_path_from_package_id( - package_id=DUMMY_SERVICE + package_id=package_id ) ), "--key", str(ETHEREUM_KEY_DEPLOYER), - *DEFAULT_SERVICE_MINT_PARAMETERS, + "--nft", + "Qmbh9SQLbNRawh9Km3PMEDSxo77k1wib8fYZUdZkhPBiev", + *parameters, ), ) self.cli_runner.mix_stderr = True assert result.exit_code == 1, result.output assert ( - "Service mint failed with following error; Cannot connect to the given RPC" - in result.stderr + "Dependency verification failed; Error connecting to the IPFS gateway" + in result.stdout ) def test_bad_owner_string( @@ -286,9 +384,7 @@ def test_bad_owner_string( ) -> None: """Test connection error.""" - with mock.patch( - "autonomy.cli.helpers.chain.get_on_chain_dependencies", return_value=[1] - ): + with mock.patch("autonomy.cli.helpers.chain.verify_service_dependencies"): result = self.run_cli( commands=( "service", @@ -308,77 +404,19 @@ def test_bad_owner_string( assert result.exit_code == 1, result.output assert "Invalid owner address 0xowner" in result.stderr - def test_fail_token_id_retrieve( - self, - ) -> None: - """Test token id retrieval failure.""" - - with mock.patch.object( - registry_contracts, "_component_registry", DummyContract() - ), mock.patch("autonomy.chain.mint.transact"): - result = self.run_cli( - commands=( - DUMMY_PROTOCOL.package_type.value, - str( - DUMMY_PACKAGE_MANAGER.package_path_from_package_id( - package_id=DUMMY_PROTOCOL - ) - ), - "--key", - str(ETHEREUM_KEY_DEPLOYER), - ), - ) - - assert result.exit_code == 1, result.output - assert ( - "Component mint was successful but token ID retrieving failed with following error; " - "Connection interrupted while waiting for the unitId emit event" - in result.stderr - ) - - def test_fail_token_id_retrieve_service( - self, - ) -> None: - """Test token id retrieval failure.""" - - with mock.patch.object( - registry_contracts, "_service_registry", DummyContract() - ), mock.patch("autonomy.chain.mint.transact"), mock.patch( - "autonomy.cli.helpers.chain.get_on_chain_dependencies", - return_value=[1], - ): - result = self.run_cli( - commands=( - DUMMY_SERVICE.package_type.value, - str( - DUMMY_PACKAGE_MANAGER.package_path_from_package_id( - DUMMY_SERVICE - ) - ), - "--key", - str(ETHEREUM_KEY_DEPLOYER), - *DEFAULT_SERVICE_MINT_PARAMETERS, - ), - ) - - assert result.exit_code == 1, result.output - assert ( - "Service mint was successful but token ID retrieving failed with following error; " - "Connection interrupted while waiting for the unitId emit event" - in result.stderr - ) - def test_fail_dependency_does_not_match_service( self, ) -> None: """Test token id retrieval failure.""" - - with mock.patch( - "autonomy.cli.helpers.chain.get_on_chain_dependencies", - return_value=[2], + with mock.patch.object( + ChainConfigs, "get", return_value=ChainConfigs.local + ), mock.patch( + "autonomy.chain.utils.resolve_component_id", + return_value={"name": "skill/author/name"}, ): result = self.run_cli( commands=( + "--use-ethereum", DUMMY_SERVICE.package_type.value, str( DUMMY_PACKAGE_MANAGER.package_path_from_package_id( @@ -387,13 +425,15 @@ def test_fail_dependency_does_not_match_service( ), "--key", str(ETHEREUM_KEY_DEPLOYER), + "--nft", + "Qmbh9SQLbNRawh9Km3PMEDSxo77k1wib8fYZUdZkhPBiev", *DEFAULT_SERVICE_MINT_PARAMETERS, ), ) assert result.exit_code == 1, result.output assert ( - "Agent ID not found in the list of on-chain agent IDs related to agent defined in the service" + "On chain ID of the agent does not match with the one in the service configuration" in result.stderr ) @@ -403,12 +443,14 @@ def test_fail_dependency_does_not_match_component( """Test token id retrieval failure.""" with mock.patch.object( - SubgraphClient, - "getRecordByPackageHash", - return_value={"units": []}, + ChainConfigs, "get", return_value=ChainConfigs.local + ), mock.patch( + "autonomy.chain.utils.resolve_component_id", + return_value={"name": "skill/author/name"}, ): result = self.run_cli( commands=( + "--use-ethereum", DUMMY_CONNECTION.package_type.value, str( DUMMY_PACKAGE_MANAGER.package_path_from_package_id( @@ -417,10 +459,57 @@ def test_fail_dependency_does_not_match_component( ), "--key", str(ETHEREUM_KEY_DEPLOYER), + "-d", + "1", + "--nft", + "Qmbh9SQLbNRawh9Km3PMEDSxo77k1wib8fYZUdZkhPBiev", ), ) assert result.exit_code == 1, result.output assert ( - "No on chain registration found for following dependencies" in result.stderr + "On chain dependency with id 1 and public ID author/name:any not found in the local package configuration" + in result.stderr ) + + def test_dry_run(self) -> None: + """Test dry run.""" + result = self.run_cli( + commands=( + "--dry-run", + DUMMY_PROTOCOL.package_type.value, + str( + DUMMY_PACKAGE_MANAGER.package_path_from_package_id( + package_id=DUMMY_PROTOCOL + ) + ), + "--key", + str(ETHEREUM_KEY_DEPLOYER), + ) + ) + assert result.exit_code == 0, result.stderr + assert "=== Dry run output ===" in result.output + + +class TestConnectionError(BaseCliTest): + """Test connection error.""" + + cli_options = ("mint",) + + def test_connection_error(self) -> None: + """Test connection error.""" + self.cli_runner.mix_stderr = False + result = self.run_cli( + commands=( + "protocol", + str( + DUMMY_PACKAGE_MANAGER.package_path_from_package_id( + package_id=DUMMY_PROTOCOL + ) + ), + "--key", + str(ETHEREUM_KEY_DEPLOYER), + ), + ) + assert result.exit_code == 1, result.output + assert "RPCError(Cannot connect to the given RPC)" in result.stderr diff --git a/tests/test_autonomy/test_cli/test_replay/test_agent.py b/tests/test_autonomy/test_cli/test_replay/test_agent.py index a413e6f53e..f98f65e356 100644 --- a/tests/test_autonomy/test_cli/test_replay/test_agent.py +++ b/tests/test_autonomy/test_cli/test_replay/test_agent.py @@ -94,10 +94,10 @@ def setup(self) -> None: super().setup() shutil.copytree( - self.packages_dir / "valory" / "services" / "hello_world", - self.t / "hello_world", + self.packages_dir / "valory" / "services" / "register_reset", + self.t / "register_reset", ) - os.chdir(self.t / "hello_world") + os.chdir(self.t / "register_reset") def test_run(self) -> None: """Test run.""" diff --git a/tests/test_autonomy/test_cli/test_replay/test_tendermint.py b/tests/test_autonomy/test_cli/test_replay/test_tendermint.py index 7ccfb1704b..cb9dc61984 100644 --- a/tests/test_autonomy/test_cli/test_replay/test_tendermint.py +++ b/tests/test_autonomy/test_cli/test_replay/test_tendermint.py @@ -88,15 +88,15 @@ def setup(self) -> None: """Setup.""" super().setup() shutil.copytree( - self.packages_dir / "valory" / "services" / "hello_world", - self.t / "hello_world", + self.packages_dir / "valory" / "services" / "register_reset", + self.t / "register_reset", ) os.chdir(self.t) def test_run(self) -> None: """Test run.""" - os.chdir(self.t / "hello_world") + os.chdir(self.t / "register_reset") with OS_ENV_PATCH: result = self.cli_runner.invoke( cli, @@ -144,7 +144,6 @@ def test_run(self) -> None: ), mock.patch.object(TendermintNetwork, "stop") as stop_mock, mock.patch.object( flask.Flask, "run", new=ctrl_c ): - result = self.run_cli(("--build", str(self.t / DEFAULT_BUILD_FOLDER))) assert result.exit_code == 0, result.output stop_mock.assert_any_call() diff --git a/tests/test_autonomy/test_cli/test_service/test_service_manager.py b/tests/test_autonomy/test_cli/test_service/test_service_manager.py index 923b15d18b..313ad37d96 100644 --- a/tests/test_autonomy/test_cli/test_service/test_service_manager.py +++ b/tests/test_autonomy/test_cli/test_service/test_service_manager.py @@ -19,15 +19,30 @@ """Test service management.""" -from typing import Optional - +import binascii +from typing import List, Optional +from unittest import mock + +import pytest +from aea.components.base import load_aea_package +from aea.configurations.data_types import PackageType +from aea.configurations.loader import load_configuration_object +from aea.contracts.base import Contract +from aea.crypto.base import Crypto from aea.crypto.registries import make_crypto from aea_test_autonomy.configurations import ETHEREUM_KEY_PATH_5 from aea_test_autonomy.fixture_helpers import registries_scope_class # noqa: F401 from click.testing import Result +from hexbytes import HexBytes +from web3 import HTTPProvider, Web3 -from autonomy.chain.service import activate_service, register_instance +from autonomy.chain.base import ServiceState, registry_contracts +from autonomy.chain.config import ChainType +from autonomy.chain.constants import ERC20_TOKEN_ADDRESS_LOCAL, HardhatAddresses +from autonomy.chain.service import get_service_info +from autonomy.cli.helpers.chain import ServiceHelper +from tests.conftest import ROOT_DIR from tests.test_autonomy.test_chain.base import ( AGENT_ID, BaseChainInteractionTest, @@ -41,6 +56,7 @@ DEFAULT_AGENT_INSTANCE_ADDRESS = ( "0x976EA74026E726554dB657fA54763abd0C3a0aa9" # a key from default hardhat keys ) +MAX_DEPLOY_ATTEMPTS = 5 class BaseServiceManagerTest(BaseChainInteractionTest): @@ -51,44 +67,57 @@ class BaseServiceManagerTest(BaseChainInteractionTest): def mint_service( self, + number_of_slots_per_agent: int = NUMBER_OF_SLOTS_PER_AGENT, + threshold: int = THRESHOLD, ) -> int: """Mint service component""" - service_id = self.mint_component( - package_id=DUMMY_SERVICE, - service_mint_parameters=dict( - agent_ids=[AGENT_ID], - number_of_slots_per_agent=[NUMBER_OF_SLOTS_PER_AGENT], - cost_of_bond_per_agent=[COST_OF_BOND_FOR_AGENT], - threshold=THRESHOLD, - ), - ) + with mock.patch("autonomy.cli.helpers.chain.verify_service_dependencies"): + service_id = self.mint_component( + package_id=DUMMY_SERVICE, + service_mint_parameters=dict( + agent_ids=[AGENT_ID], + number_of_slots_per_agent=[number_of_slots_per_agent], + cost_of_bond_per_agent=[COST_OF_BOND_FOR_AGENT], + threshold=threshold, + ), + ) assert isinstance(service_id, int) return service_id def activate_service(self, service_id: int) -> None: """Activate service""" - activate_service( - ledger_api=self.ledger_api, - crypto=self.crypto, - chain_type=self.chain_type, - service_id=service_id, - ) + self.service_manager.activate(service_id=service_id) def register_instances( self, service_id: int, agent_instance: Optional[str] = None ) -> None: """Register agent instance.""" - - register_instance( - ledger_api=self.ledger_api, - crypto=self.crypto, - chain_type=self.chain_type, + self.service_manager.register_instance( service_id=service_id, instances=[(agent_instance or make_crypto("ethereum").address)], agent_ids=[AGENT_ID], ) + def deploy_service( + self, + service_id: int, + reuse_multisig: bool = False, + ) -> None: + """Deploy service.""" + self.service_manager.deploy( + service_id=service_id, + reuse_multisig=reuse_multisig, + ) + + def terminate_service(self, service_id: int) -> None: + """Terminate service.""" + self.service_manager.terminate(service_id=service_id) + + def unbond_service(self, service_id: int) -> None: + """Unbond service.""" + self.service_manager.unbond(service_id=service_id) + class TestServiceManager(BaseServiceManagerTest): """Test service manager.""" @@ -166,7 +195,6 @@ def _run_command(service_id: str) -> Result: result = _run_command(str(service_id)) # Will fail becaue the agent instance is already registered assert result.exit_code == 1, result.stdout - assert "Instance registration failed" in result.stderr assert "AgentInstanceRegistered" in result.stderr def test_deploy( @@ -216,3 +244,523 @@ def _run_command(service_id: str) -> Result: # Will fail becaue the service is already deployed assert result.exit_code == 1, result.stdout assert "Service needs to be in finished registration state" in result.stderr + + def test_terminate( + self, + ) -> None: + """Test terminate service.""" + + def _run_command(service_id: str) -> Result: + """Run command and return result""" + return self.run_cli( + commands=( + "terminate", + service_id, + "--key", + str(self.key_file), + ) + ) + + result = _run_command("100") + assert result.exit_code == 1, result.output + assert "Service does not exist" in result.stderr + + service_id = self.mint_service() + + result = _run_command(str(service_id)) + assert result.exit_code == 1, result.output + assert "Service not active" in result.stderr + + self.activate_service( + service_id=service_id, + ) + for _ in range(NUMBER_OF_SLOTS_PER_AGENT): + self.register_instances( + service_id=service_id, + ) + self.deploy_service(service_id=service_id) + + result = _run_command(str(service_id)) + + assert result.exit_code == 0, result.stderr + assert "Service terminated succesfully" in result.output + + result = _run_command(str(service_id)) + + # Will fail becaue the service is already deployed + assert result.exit_code == 1, result.stdout + assert "Service already terminated" in result.stderr + + def test_unbond( + self, + ) -> None: + """Test unbond service.""" + + def _run_command(service_id: str) -> Result: + """Run command and return result""" + return self.run_cli( + commands=( + "unbond", + service_id, + "--key", + str(self.key_file), + ) + ) + + result = _run_command("100") + assert result.exit_code == 1, result.output + assert "Service does not exist" in result.stderr + + service_id = self.mint_service() + + self.activate_service( + service_id=service_id, + ) + for _ in range(NUMBER_OF_SLOTS_PER_AGENT): + self.register_instances( + service_id=service_id, + ) + self.deploy_service(service_id=service_id) + + result = _run_command(str(service_id)) + assert result.exit_code == 1, result.output + assert "Service needs to be in terminated-bonded state" in result.stderr + + self.terminate_service(service_id=service_id) + + result = _run_command(str(service_id)) + + assert result.exit_code == 0, result.stderr + assert "Service unbonded succesfully" in result.output + + result = _run_command(str(service_id)) + + # Will fail becaue the service is already deployed + assert result.exit_code == 1, result.stdout + assert "Service needs to be in terminated-bonded state" in result.stderr + + def test_info( + self, + ) -> None: + """Test service info.""" + + def _run_check(service_id: str, message: str) -> Result: + """Run command and return result""" + result = self.run_cli(commands=("info", service_id)) + assert result.exit_code == 0 + assert message in result.output + + _run_check("100", message=ServiceState.NON_EXISTENT.name) + + service_id = self.mint_service() + _run_check( + service_id=str(service_id), message=ServiceState.PRE_REGISTRATION.name + ) + + self.activate_service(service_id=service_id) + _run_check( + service_id=str(service_id), message=ServiceState.ACTIVE_REGISTRATION.name + ) + + for _ in range(NUMBER_OF_SLOTS_PER_AGENT): + self.register_instances( + service_id=service_id, + ) + _run_check( + service_id=str(service_id), message=ServiceState.FINISHED_REGISTRATION.name + ) + + self.deploy_service(service_id=service_id) + _run_check(service_id=str(service_id), message=ServiceState.DEPLOYED.name) + + self.terminate_service(service_id=service_id) + _run_check( + service_id=str(service_id), message=ServiceState.TERMINATED_BONDED.name + ) + + self.unbond_service(service_id=service_id) + _run_check( + service_id=str(service_id), message=ServiceState.PRE_REGISTRATION.name + ) + + def test_dry_run(self) -> None: + """Test dry run.""" + service_id = self.mint_service() + result = self.run_cli( + commands=( + "--dry-run", + "activate", + str(service_id), + "--key", + str(self.key_file), + ) + ) + assert result.exit_code == 0, result.stderr + assert "=== Dry run output ===" in result.output + + +class TestERC20AsBond(BaseServiceManagerTest): + """Test ERC20 token as bond.""" + + def setup(self) -> None: + """Setup test.""" + super().setup() + erc20_instance = Contract.from_dir( + ROOT_DIR / "packages" / "valory" / "contracts" / "erc20" + ).get_instance( + ledger_api=self.ledger_api, + contract_address=ERC20_TOKEN_ADDRESS_LOCAL, + ) + tx = erc20_instance.functions.mint( + self.crypto.address, int(1e18) + ).build_transaction( + { + "from": self.crypto.address, + "gas": 200001, + "gasPrice": 30000, + "nonce": self.ledger_api.api.eth.get_transaction_count( + self.crypto.address + ), + } + ) + stx = self.crypto.entity.sign_transaction(tx) + tx_digext = self.ledger_api.api.eth.send_raw_transaction(stx.rawTransaction) + while True: + try: + return self.ledger_api.api.eth.get_transaction_receipt(tx_digext) + except Exception: # nosec + continue + + def mint(self) -> int: + """Mint service with token""" + + with mock.patch("autonomy.cli.helpers.chain.verify_service_dependencies"): + service_id = self.mint_component( + package_id=DUMMY_SERVICE, + service_mint_parameters=dict( + agent_ids=[AGENT_ID], + number_of_slots_per_agent=[NUMBER_OF_SLOTS_PER_AGENT], + cost_of_bond_per_agent=[COST_OF_BOND_FOR_AGENT], + threshold=THRESHOLD, + token=ERC20_TOKEN_ADDRESS_LOCAL, + ), + ) + assert isinstance(service_id, int) + return service_id + + def test_mint(self) -> None: + """Test mint with ERC20 token as bond.""" + service_id = self.mint() + assert ( + ServiceHelper( + service_id=service_id, + chain_type=ChainType.LOCAL, + key=self.key_file, + ) + .check_is_service_token_secured(token=ERC20_TOKEN_ADDRESS_LOCAL) + .token_secured + is True + ) + + def test_activate(self) -> None: + """Test activate with token.""" + service_id = self.mint() + result = self.run_cli( + commands=( + "activate", + str(service_id), + "--key", + str(self.key_file), + "--token", + ERC20_TOKEN_ADDRESS_LOCAL, + ) + ) + assert result.exit_code == 0, result.stderr + + def test_activate_failure(self) -> None: + """Test activate with token.""" + service_id = self.mint() + result = self.run_cli( + commands=( + "activate", + str(service_id), + "--key", + str(self.key_file), + ) + ) + + assert result.exit_code == 1, result.stderr + assert ( + "Service is token secured, please provice token address using `--token` flag" + in result.stderr + ) + + def test_register_instances(self) -> None: + """Test register instances with token.""" + service_id = self.mint() + result = self.run_cli( + commands=( + "activate", + str(service_id), + "--key", + str(self.key_file), + "--token", + ERC20_TOKEN_ADDRESS_LOCAL, + ) + ) + assert result.exit_code == 0, result.stderr + + agent = make_crypto("ethereum") + result = self.run_cli( + commands=( + "register", + str(service_id), + "--key", + str(self.key_file), + "-a", + str(AGENT_ID), + "-i", + agent.address, + "--token", + ERC20_TOKEN_ADDRESS_LOCAL, + ) + ) + assert result.exit_code == 0, result.stderr + + def test_register_instances_failure(self) -> None: + """Test register instances with token.""" + service_id = self.mint() + result = self.run_cli( + commands=( + "activate", + str(service_id), + "--key", + str(self.key_file), + "--token", + ERC20_TOKEN_ADDRESS_LOCAL, + ) + ) + assert result.exit_code == 0, result.stderr + + agent = make_crypto("ethereum") + result = self.run_cli( + commands=( + "register", + str(service_id), + "--key", + str(self.key_file), + "-a", + str(AGENT_ID), + "-i", + agent.address, + ) + ) + assert result.exit_code == 1, result.output + assert ( + "Service is token secured, please provice token address using `--token` flag" + in result.stderr + ) + + +class TestServiceRedeploymentWithSameMultisig(BaseServiceManagerTest): + """Test service deployment with same multisig.""" + + def setup(self) -> None: + """Setup class.""" + super().setup() + self.ledger_api._api = Web3( + HTTPProvider( + endpoint_uri="http://127.0.0.1:8545", + request_kwargs={ + "timeout": 120, + }, + ), + ) + self.ledger_api.api.eth.default_account = self.crypto.address + + def fund(self, address: str, amount: int = 1) -> None: + """Fund an address.""" + raw_tx = { + "to": address, + "from": self.crypto.address, + "value": self.ledger_api.api.to_wei(amount, "ether"), + "gas": 100000, + "chainId": self.ledger_api.api.eth.chain_id, + "gasPrice": self.ledger_api.api.eth.gas_price, + "nonce": self.ledger_api.api.eth.get_transaction_count(self.crypto.address), + } + signed_tx = self.crypto.entity.sign_transaction(raw_tx) + self.ledger_api.api.eth.send_raw_transaction(signed_tx.rawTransaction) + + def generate_and_fund_keys(self, n: int = 4) -> List[Crypto]: + """Generate and fund keys.""" + keys = [] + for _ in range(n): + crypto = make_crypto("ethereum") + keys.append(crypto) + self.fund(address=keys[0].address) + return keys + + def remove_owners(self, multisig_address: str, owners: List[Crypto]) -> None: + """Remove owners.""" + + # Load packages in the memory. + packages_dir = ROOT_DIR / "packages" / "valory" + for package_type, package_path in ( + ( + PackageType.CONTRACT, + packages_dir / "contracts" / "gnosis_safe_proxy_factory", + ), + (PackageType.CONTRACT, packages_dir / "contracts" / "gnosis_safe"), + (PackageType.CONTRACT, packages_dir / "contracts" / "multisend"), + ( + PackageType.SKILL, + packages_dir / "skills" / "transaction_settlement_abci", + ), + ): + config_obj = load_configuration_object( + package_type=package_type, directory=package_path + ) + config_obj.directory = package_path + load_aea_package(configuration=config_obj) + + from packages.valory.contracts.gnosis_safe.contract import SafeOperation + from packages.valory.contracts.multisend.contract import MultiSendOperation + from packages.valory.skills.transaction_settlement_abci.payload_tools import ( + hash_payload_to_hex, + skill_input_hex_to_payload, + ) + + multisend_address = HardhatAddresses.multisend + threshold = 1 + owner_to_swap = owners[0].address + owners_to_remove = reversed(owners[1:]) + multisend_txs = [] + + for owner in owners_to_remove: + txd = registry_contracts.gnosis_safe.get_remove_owner_data( + ledger_api=self.ledger_api, + contract_address=multisig_address, + owner=owner.address, + threshold=threshold, + ).get("data") + multisend_txs.append( + { + "operation": MultiSendOperation.CALL, + "to": multisig_address, + "value": 0, + "data": HexBytes(bytes.fromhex(txd[2:])), + } + ) + txd = registry_contracts.gnosis_safe.get_swap_owner_data( + ledger_api=self.ledger_api, + contract_address=multisig_address, + old_owner=self.ledger_api.api.to_checksum_address(owner_to_swap), + new_owner=self.ledger_api.api.to_checksum_address(self.crypto.address), + ).get("data") + multisend_txs.append( + { + "operation": MultiSendOperation.CALL, + "to": multisig_address, + "value": 0, + "data": HexBytes(txd[2:]), + } + ) + + multisend_txd = registry_contracts.multisend.get_tx_data( + ledger_api=self.ledger_api, + contract_address=multisend_address, + multi_send_txs=multisend_txs, + ).get("data") + multisend_data = bytes.fromhex(multisend_txd[2:]) + + safe_tx_hash = registry_contracts.gnosis_safe.get_raw_safe_transaction_hash( + ledger_api=self.ledger_api, + contract_address=multisig_address, + to_address=multisend_address, + value=0, + data=multisend_data, + safe_tx_gas=0, + operation=SafeOperation.DELEGATE_CALL.value, + ).get("tx_hash")[2:] + + payload_data = hash_payload_to_hex( + safe_tx_hash=safe_tx_hash, + ether_value=0, + safe_tx_gas=0, + to_address=multisend_address, + data=multisend_data, + ) + + tx_params = skill_input_hex_to_payload(payload=payload_data) + safe_tx_bytes = binascii.unhexlify(tx_params["safe_tx_hash"]) + owner_to_signature = {} + for owner_crypto in owners: + signature = owner_crypto.sign_message( + message=safe_tx_bytes, + is_deprecated_mode=True, + ) + owner_to_signature[ + self.ledger_api.api.to_checksum_address(owner_crypto.address) + ] = signature[2:] + + tx = registry_contracts.gnosis_safe.get_raw_safe_transaction( + ledger_api=self.ledger_api, + contract_address=multisig_address, + sender_address=owners[0].address, + owners=tuple([owner.address for owner in owners]), + to_address=tx_params["to_address"], + value=tx_params["ether_value"], + data=tx_params["data"], + safe_tx_gas=tx_params["safe_tx_gas"], + signatures_by_owner=owner_to_signature, + operation=SafeOperation.DELEGATE_CALL.value, + ) + stx = owners[0].sign_transaction(tx) + tx_digest = self.ledger_api.send_signed_transaction(stx) + self.ledger_api.get_transaction_receipt(tx_digest) + + @pytest.mark.parametrize( + argnames="n_owners", + argvalues=(1, 2), + ) + def test_redeploy(self, n_owners: int) -> None: + """Test redeploy service with same multisig.""" + instances = self.generate_and_fund_keys(n=n_owners) + service_id = self.mint_service( + number_of_slots_per_agent=n_owners, threshold=n_owners + ) + self.activate_service(service_id=service_id) + for instance in instances: + self.register_instances( + service_id=service_id, agent_instance=instance.address + ) + self.deploy_service(service_id=service_id) + self.terminate_service(service_id=service_id) + self.unbond_service(service_id=service_id) + _, multisig_address, *_ = get_service_info( + ledger_api=self.ledger_api, + chain_type=ChainType.LOCAL, + token_id=service_id, + ) + self.remove_owners(multisig_address=multisig_address, owners=instances) + + new_instances = self.generate_and_fund_keys(n=n_owners) + self.activate_service(service_id=service_id) + for instance in new_instances: + self.register_instances( + service_id=service_id, agent_instance=instance.address + ) + + self.deploy_service(service_id=service_id, reuse_multisig=True) + _, multisig_address_redeployed, *_ = get_service_info( + ledger_api=self.ledger_api, + chain_type=ChainType.LOCAL, + token_id=service_id, + ) + assert multisig_address_redeployed == multisig_address + safe_owners = registry_contracts.gnosis_safe.get_owners( + ledger_api=self.ledger_api, + contract_address=multisig_address, + ).get("owners") + assert set(safe_owners) == set([instance.address for instance in new_instances]) diff --git a/tests/test_autonomy/test_deploy/test_deployment_generators.py b/tests/test_autonomy/test_deploy/test_deployment_generators.py index c2b896dedc..5b2de7fccb 100644 --- a/tests/test_autonomy/test_deploy/test_deployment_generators.py +++ b/tests/test_autonomy/test_deploy/test_deployment_generators.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- # ------------------------------------------------------------------------------ # -# Copyright 2022 Valory AG +# Copyright 2022-2023 Valory AG # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -27,6 +27,7 @@ import pytest from aea.configurations.data_types import PublicId from aea.helpers.base import cd +from aea_test_autonomy.docker.base import skip_docker_tests from autonomy.configurations.base import Service from autonomy.deploy.base import BaseDeploymentGenerator, ServiceBuilder @@ -50,6 +51,7 @@ def get_dummy_service() -> Service: return Service(name="dummy", author="default", agent=AGENT) +@skip_docker_tests @pytest.mark.parametrize("generator_cls", (DockerComposeGenerator, KubernetesGenerator)) @pytest.mark.parametrize("image_version", [None, "0.1.0"]) @pytest.mark.parametrize("use_hardhat", [False, True]) diff --git a/tests/test_autonomy/test_deploy/test_image.py b/tests/test_autonomy/test_deploy/test_image.py new file mode 100644 index 0000000000..ccd899e657 --- /dev/null +++ b/tests/test_autonomy/test_deploy/test_image.py @@ -0,0 +1,42 @@ +# -*- coding: utf-8 -*- +# ------------------------------------------------------------------------------ +# +# Copyright 2023 Valory AG +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# ------------------------------------------------------------------------------ + +"""Test image build helpers.""" + +from aea.configurations.data_types import Dependency + +from autonomy.deploy.image import generate_dependency_flag_var + + +def test_generate_dependency_flag_var() -> None: + """Test generate_dependency_flag_var method.""" + + dependencies = ( + Dependency(name="some-package", version="==1.0.0"), + Dependency( + name="other-package", + git="https://github.com/author/some_package", + ref="79342a93079648ef03ab5aaf14978068fc96587a", + ), + ) + + assert generate_dependency_flag_var(dependencies=dependencies) == ( + "-e some-package==1.0.0 " + "-e git+https://github.com/author/some_package@79342a93079648ef03ab5aaf14978068fc96587a#egg=other-package" + ) diff --git a/tests/test_autonomy/test_deploy/test_network_builder.py b/tests/test_autonomy/test_deploy/test_network_builder.py new file mode 100644 index 0000000000..fa3931189b --- /dev/null +++ b/tests/test_autonomy/test_deploy/test_network_builder.py @@ -0,0 +1,100 @@ +# -*- coding: utf-8 -*- +# ------------------------------------------------------------------------------ +# +# Copyright 2023 Valory AG +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# ------------------------------------------------------------------------------ + +"""Tests for network builder.""" + +import ipaddress +from typing import Any, cast +from unittest import mock + +from aea_test_autonomy.docker.base import skip_docker_tests +from docker.client import NetworkCollection + +from autonomy.deploy.generators.docker_compose.base import Network + + +BASE_SUBNET = cast( + ipaddress.IPv4Network, + ipaddress.ip_network("192.168.21.0/24"), +) + + +@skip_docker_tests +class TestNetworkBuilder: + """Test `NetworkBuilder`""" + + @staticmethod + def patch_docker() -> Any: + """Patch docker""" + return + + def test_base(self) -> None: + """Test initialization.""" + network = Network( + name="test_network", + base=BASE_SUBNET, + ) + + assert network.build() == BASE_SUBNET + assert network.next_address == str(BASE_SUBNET.network_address + 2) + + def test_next_subnet(self) -> None: + """Test next available subnet.""" + + with mock.patch.object( + NetworkCollection, + "list", + return_value=[ + mock.MagicMock( + attrs={ + "Name": "test_network_1", + "IPAM": {"Config": [{"Subnet": str(BASE_SUBNET)}]}, + } + ), + ], + ): + network = Network( + name="test_network", + base=BASE_SUBNET, + ) + assert network.subnet == Network.next_subnet(subnet=BASE_SUBNET) + + def test_subnet_exists(self) -> None: + """Test next available subnet.""" + network = Network( + name="test_network", + base=BASE_SUBNET, + ) + with mock.patch.object( + NetworkCollection, + "list", + return_value=[ + mock.MagicMock( + attrs={ + "Name": "abci_build_test_network", + "IPAM": { + "Config": [ + {"Subnet": str(Network.next_subnet(subnet=BASE_SUBNET))} + ] + }, + } + ), + ], + ): + assert network.build() == Network.next_subnet(subnet=BASE_SUBNET) diff --git a/tests/test_autonomy/test_deploy/test_service_specification.py b/tests/test_autonomy/test_deploy/test_service_specification.py index 43f878a857..352f206171 100644 --- a/tests/test_autonomy/test_deploy/test_service_specification.py +++ b/tests/test_autonomy/test_deploy/test_service_specification.py @@ -33,7 +33,6 @@ import yaml from autonomy.deploy.base import ( - ABCI_HOST_TEMPLATE, DEFAULT_ABCI_PORT, ENV_VAR_AEA_AGENT, ENV_VAR_AEA_PASSWORD, @@ -126,7 +125,6 @@ def test_initialize( self.keys_path, ) - assert spec.private_keys_password is None assert spec.agent_instances is None assert len(spec.keys) == 1 @@ -145,11 +143,29 @@ def test_generate_agents( assert len(agents) == 1, agents agent = spec.generate_agent(0) - assert len(agent.keys()) == 10, agent + assert len(agent.keys()) == 11, agent spec.service.overrides = [] agent = spec.generate_agent(0) - assert len(agent.keys()) == 3, agent + assert len(agent.keys()) == 4, agent + + def test_get_maximum_participants( + self, + ) -> None: + """Test get_maximum_participants.""" + self._write_service(get_dummy_service_config(file_number=0)) + spec = ServiceBuilder.from_dir( + self.service_path, + self.keys_path, + ) + + spec._all_participants = list(map(str, range(2))) + assert spec.get_maximum_participants() == 2 + + with mock.patch.object(spec, attribute="verify_agent_instances"): + spec._all_participants = [] + spec.agent_instances = list(map(str, range(3))) + assert spec.get_maximum_participants() == 3 def test_generate_common_vars( self, @@ -166,11 +182,7 @@ def test_generate_common_vars( assert all(var in common_vars_without_password for var in COMMON_VARS[:-1]) assert common_vars_without_password[ENV_VAR_AEA_AGENT] == spec.service.agent - spec = ServiceBuilder.from_dir( # nosec - self.service_path, - self.keys_path, - private_keys_password="some_password", - ) + spec = ServiceBuilder.from_dir(self.service_path, self.keys_path) # nosec common_vars_without_password = spec.generate_common_vars(agent_n=0) assert all(var in common_vars_without_password for var in COMMON_VARS) @@ -266,13 +278,15 @@ def test_try_update_runtime_params_singular( assert skill_config["models"]["params"]["args"][ TENDERMINT_URL_PARAM - ] == TENDERMINT_NODE.format(0) + ] == TENDERMINT_NODE.format(host=spec.get_tm_container_name(index=0)) assert skill_config["models"]["params"]["args"][ TENDERMINT_COM_URL_PARAM - ] == TENDERMINT_COM.format(0) + ] == TENDERMINT_COM.format(host=spec.get_tm_container_name(index=0)) assert skill_config["models"]["params"]["args"][ TENDERMINT_P2P_URL_PARAM - ] == TENDERMINT_P2P_URL.format(0, TENDERMINT_P2P_PORT) + ] == TENDERMINT_P2P_URL.format( + host=spec.get_tm_container_name(index=0), port=TENDERMINT_P2P_PORT + ) def test_try_update_runtime_params_multiple( self, @@ -307,13 +321,18 @@ def test_try_update_runtime_params_multiple( assert skill_config[agent_idx]["models"]["params"]["args"][ TENDERMINT_URL_PARAM - ] == TENDERMINT_NODE.format(agent_idx) + ] == TENDERMINT_NODE.format( + host=spec.get_tm_container_name(index=agent_idx) + ) assert skill_config[agent_idx]["models"]["params"]["args"][ TENDERMINT_COM_URL_PARAM - ] == TENDERMINT_COM.format(agent_idx) + ] == TENDERMINT_COM.format(host=spec.get_tm_container_name(index=agent_idx)) assert skill_config[agent_idx]["models"]["params"]["args"][ TENDERMINT_P2P_URL_PARAM - ] == TENDERMINT_P2P_URL.format(agent_idx, TENDERMINT_P2P_PORT) + ] == TENDERMINT_P2P_URL.format( + host=spec.get_tm_container_name(index=agent_idx), + port=TENDERMINT_P2P_PORT, + ) def test_update_tm_p2p_endpoint_from_env( self, @@ -335,10 +354,10 @@ def test_update_tm_p2p_endpoint_from_env( assert skill_config["models"]["params"]["args"][ TENDERMINT_URL_PARAM - ] == TENDERMINT_NODE.format(0) + ] == TENDERMINT_NODE.format(host=spec.get_tm_container_name(index=0)) assert skill_config["models"]["params"]["args"][ TENDERMINT_COM_URL_PARAM - ] == TENDERMINT_COM.format(0) + ] == TENDERMINT_COM.format(host=spec.get_tm_container_name(index=0)) assert ( skill_config["models"]["params"]["args"][TENDERMINT_P2P_URL_PARAM] == url @@ -381,7 +400,7 @@ def test_try_update_abci_connection_params_singular( spec.try_update_abci_connection_params() conn_config, *_ = spec.service.overrides - assert conn_config["config"]["host"] == ABCI_HOST_TEMPLATE.format(0) + assert conn_config["config"]["host"] == spec.get_abci_container_name(index=0) assert conn_config["config"]["port"] == DEFAULT_ABCI_PORT def test_try_update_abci_connection_params_multiple( @@ -402,7 +421,9 @@ def test_try_update_abci_connection_params_multiple( ] for idx in range(spec.service.number_of_agents): - assert conn_config[idx]["config"]["host"] == ABCI_HOST_TEMPLATE.format(idx) + assert conn_config[idx]["config"]["host"] == spec.get_abci_container_name( + index=idx + ) assert conn_config[idx]["config"]["port"] == DEFAULT_ABCI_PORT def test_try_update_abci_connection_params_kubernetes( diff --git a/tests/test_autonomy/test_images/test_autonomy.py b/tests/test_autonomy/test_images/test_autonomy.py index 8bc8cb46a7..81a14dc966 100644 --- a/tests/test_autonomy/test_images/test_autonomy.py +++ b/tests/test_autonomy/test_images/test_autonomy.py @@ -62,4 +62,4 @@ def test_image(self) -> None: container.wait() - assert b"requirements.txt" in container.logs() + assert b"scripts" in container.logs() diff --git a/tests/test_autonomy/test_images/test_autonomy_user.py b/tests/test_autonomy/test_images/test_autonomy_user.py new file mode 100644 index 0000000000..eeb6c75c2c --- /dev/null +++ b/tests/test_autonomy/test_images/test_autonomy_user.py @@ -0,0 +1,70 @@ +# -*- coding: utf-8 -*- +# ------------------------------------------------------------------------------ +# +# Copyright 2023 Valory AG +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# ------------------------------------------------------------------------------ + +"""Test `valory/open-autonomy-user` image.""" + +from pathlib import Path +from typing import cast + +import docker +import pytest +from docker.models.containers import Container + +from autonomy import __version__ +from autonomy.constants import AUTONOMY_IMAGE_NAME +from autonomy.deploy.constants import DOCKERFILES + +from tests.conftest import ROOT_DIR +from tests.test_autonomy.test_images.base import BaseImageBuildTest + + +@pytest.mark.skip( + reason=( + "Temporary skip untile we figure out the volume size issue " + "https://forums.docker.com/t/error-response-from-daemon-error-creating-overlay-mount-to-var-lib-docker-overlay2-merged-no-such-file-or-directory-error-failed-to-start-containers-mydocker/123365" + ) +) +class TestOpenAutonomyUserImage(BaseImageBuildTest): + """Test image build and run.""" + + client: docker.DockerClient + path: Path = ROOT_DIR / "deployments" / DOCKERFILES / "autonomy-user" + tag: str = f"{AUTONOMY_IMAGE_NAME}:latest" + + def test_image(self) -> None: + """Test image build.""" + + success, output = self.build_image( + path=self.path, + tag=self.tag, + ) + + assert success, output + assert "Successfully built" in output + + container = cast( + Container, + self.client.containers.run( + image=self.tag, + command=["-c", "autonomy --version"], + detach=True, + ), + ) + container.wait() + assert __version__.encode() in container.logs() diff --git a/tests/test_autonomy/test_images/test_runtime.py b/tests/test_autonomy/test_images/test_runtime.py index 053254189f..9fdd5bd985 100644 --- a/tests/test_autonomy/test_images/test_runtime.py +++ b/tests/test_autonomy/test_images/test_runtime.py @@ -38,11 +38,11 @@ ) from autonomy.deploy.constants import DOCKERFILES -from tests.conftest import ROOT_DIR, get_package_hash_from_latest_tag, skip_docker_tests +from tests.conftest import ROOT_DIR, skip_docker_tests from tests.test_autonomy.test_images.base import BaseImageBuildTest -AGENT = PackageId.from_uri_path("agent/valory/hello_world/0.1.0") +AGENT = PackageId.from_uri_path("agent/valory/offend_slash/0.1.0") TENDERMINT_IMAGE = f"{TENDERMINT_IMAGE_NAME}:{TENDERMINT_IMAGE_VERSION}" @@ -64,7 +64,7 @@ def setup_class(cls) -> None: cls.agent = str( AGENT.with_hash( - get_package_hash_from_latest_tag(package=AGENT.to_uri_path) + package_hash="bafybeibe6kgnwkuhcydk5gr3wvsybdlc7gfuzt2ia24czudsvxlbmdlrwe" ).public_id ) @@ -99,6 +99,7 @@ def test_image(self) -> None: ) assert success, output + assert "Successfully built the host dependencies" in output assert f"Successfully tagged {self.tag}" in output # check runtime @@ -123,10 +124,7 @@ def test_image(self) -> None: def _check_for_outputs() -> bool: """Check for required outputs.""" - return ( - b"Entered in the 'registration_round' round for period 0" - in agent_container.logs() - ) + return b"Starting AEA 'agent' in 'async' mode..." in agent_container.logs() try: wait_for_condition( diff --git a/tests/test_autonomy/test_images/test_tendermint.py b/tests/test_autonomy/test_images/test_tendermint.py index 48d82867b4..e70fbfaf47 100644 --- a/tests/test_autonomy/test_images/test_tendermint.py +++ b/tests/test_autonomy/test_images/test_tendermint.py @@ -36,7 +36,7 @@ @skip_docker_tests -class TestOpenAutonomyBaseImage(BaseImageBuildTest): +class TestTendermintImage(BaseImageBuildTest): """Test image build and run.""" client: docker.DockerClient @@ -89,7 +89,10 @@ def test_image(self) -> None: def _check_for_outputs() -> bool: """Check for required outputs.""" - return "abci.socketClient failed to connect" in log_file.read_text() + return ( + "abci.socketClient failed to connect" + in tm_container.logs().decode() + ) try: wait_for_condition( diff --git a/tests/test_autonomy/test_replay.py b/tests/test_autonomy/test_replay.py index 3651d3c223..0ca7ad06b6 100644 --- a/tests/test_autonomy/test_replay.py +++ b/tests/test_autonomy/test_replay.py @@ -50,7 +50,7 @@ "environment": [ "LOG_FILE=/logs/aea_0.txt", "ID=0", - "VALORY_APPLICATION=valory/hello_world:0.1.0:bafybeideb6b5k4i6z7bm3p53eydxgknmwdefo2oshcnlxthjc6oxeox7ua", + "VALORY_APPLICATION=valory/offend_slash:0.1.0:bafybeideb6b5k4i6z7bm3p53eydxgknmwdefo2oshcnlxthjc6oxeox7ua", "ABCI_HOST=abci0", f"SKILL_ORACLE_ABCI_MODELS_PARAMS_ARGS_{TENDERMINT_URL_PARAM.upper()}=http://node0:26657", f"SKILL_ORACLE_ABCI_MODELS_PARAMS_ARGS_{TENDERMINT_COM_URL_PARAM.upper()}=http://node0:8080", @@ -156,7 +156,6 @@ def test_tendermint_network() -> None: tendermint_network.run_until_interruption() with app.test_client() as client: - response = client.get("/0/tx") response_data = response.get_json() assert response_data["result"]["tx_result"]["code"] == 0 diff --git a/tests/test_base.py b/tests/test_base.py index 5e6fb83b92..f068434062 100644 --- a/tests/test_base.py +++ b/tests/test_base.py @@ -62,7 +62,7 @@ def get_test_files(package_type: PackageType) -> List[Path]: def test_version() -> None: """Test the version.""" - assert autonomy.__version__ == "0.10.2" + assert autonomy.__version__ == "0.13.9.post1" @pytest.mark.parametrize( diff --git a/tests/test_deployments/test_app.py b/tests/test_deployments/test_app.py index e8513efbfe..70babc6044 100644 --- a/tests/test_deployments/test_app.py +++ b/tests/test_deployments/test_app.py @@ -52,9 +52,6 @@ override_config_toml, update_peers, ) -from deployments.Dockerfiles.tendermint.tendermint import ( # type: ignore - TendermintParams, -) ENCODING = "utf-8" @@ -134,7 +131,6 @@ class BaseTendermintServerTest(BaseTendermintTest): app: flask.app.Flask app_context: flask.ctx.AppContext tendermint_node: TendermintNode - perform_monitoring = True debug_tendermint = False tm_status_endpoint = "http://localhost:26657/status" dump_dir: Path @@ -147,10 +143,10 @@ def setup_class(cls) -> None: os.environ["CREATE_EMPTY_BLOCKS"] = "true" os.environ["USE_GRPC"] = "false" os.environ["LOG_FILE"] = str(cls.path / "tendermint.log") + os.environ["WRITE_TO_LOG"] = "true" cls.dump_dir = Path(tempfile.mkdtemp()) cls.app, cls.tendermint_node = create_app( dump_dir=cls.dump_dir, - perform_monitoring=cls.perform_monitoring, debug=cls.debug_tendermint, ) cls.app.config["TESTING"] = True @@ -306,7 +302,6 @@ def test_get_and_update(self) -> None: genesis_config = load_genesis() with self.app.test_client() as client: - # 1. check params are in validator set response = client.get("/params") assert response.status_code == 200 @@ -428,64 +423,6 @@ def get_missing(messages: Set[str]) -> Set[str]: ) -def mock_get_node_command_kwargs() -> Dict: - """Get the node command kwargs""" - kwargs = { - "bufsize": 1, - "universal_newlines": True, - } - - # Pipe stdout and stderr even if we're not going to read to provoke the buffer fill - kwargs["stdout"] = subprocess.PIPE - kwargs["stderr"] = subprocess.STDOUT - - if platform.system() == "Windows": # pragma: nocover - kwargs["creationflags"] = subprocess.CREATE_NEW_PROCESS_GROUP # type: ignore - else: - kwargs["preexec_fn"] = os.setsid # type: ignore - - return kwargs - - -class TestTendermintBufferFailing(BaseTendermintServerTest): - """Test Tendermint buffer""" - - perform_monitoring = False # Setting this flag to False and not monitoring makes the buffer to fill and freeze Tendermint - debug_tendermint = True # This will cause more logging -> faster failure - - @classmethod - def setup_class(cls) -> None: - """Setup the test.""" - with mock.patch.object( - TendermintParams, - "get_node_command_kwargs", - return_value=mock_get_node_command_kwargs(), - ): - super().setup_class() - - @wait_for_occupied_rpc_port - def test_tendermint_buffer(self) -> None: - """Test Tendermint buffer""" - - with pytest.raises(requests.exceptions.Timeout): - # Give the test 30 seconds for it to throw a timeout - for _ in range(30): - # If it hangs for 5 seconds, we assume it's not working. - # Increasing the timeout should have no effect, - # the node is unresponsive at this point. - requests.get(self.tm_status_endpoint, timeout=5) - time.sleep(1) - - @classmethod - def teardown_class(cls) -> None: - """Teardown the test.""" - # After the test, the node has hanged. We need to kill it and not stop it. - if cls.tendermint_node._process: - cls.tendermint_node._process.kill() - cls.app_context.pop() - shutil.rmtree(cls.tm_home, ignore_errors=True, onerror=readonly_handler) - - class TestTendermintBufferWorking(BaseTendermintServerTest): """Test Tendermint buffer""" diff --git a/tests/test_deployments/test_deployments.py b/tests/test_deployments/test_deployments.py index b44a2c0341..bab7eed0cc 100644 --- a/tests/test_deployments/test_deployments.py +++ b/tests/test_deployments/test_deployments.py @@ -281,7 +281,6 @@ def test_update_agent_number_based_on_keys_file(self) -> None: builder = ServiceBuilder( service=service, keys=None, - private_keys_password=None, agent_instances=list("abcdefg"), ) assert builder.service.number_of_agents == 1_000_000 @@ -414,6 +413,7 @@ def test_validates_with_list_override(self) -> None: ) app_instance.service.check_overrides_valid(app_instance.service.overrides) + @skip_docker_tests def test_validates_with_10_agents(self) -> None: """Test functionality of deploy safe contract.""" for deployment_generator in deployment_generators: @@ -429,6 +429,7 @@ def test_validates_with_10_agents(self) -> None: app_instance.generate_agents() deployment_instance.generate() + @skip_docker_tests def test_validates_with_20_agents(self) -> None: """Test functionality of deploy safe contract.""" for deployment_generator in deployment_generators: diff --git a/tests/test_docs/helper.py b/tests/test_docs/helper.py index 27c0a6b265..1978793a22 100644 --- a/tests/test_docs/helper.py +++ b/tests/test_docs/helper.py @@ -24,12 +24,15 @@ from pathlib import Path from typing import Callable, Dict, List, Optional +import requests + from tests.conftest import ROOT_DIR IPFS_HASH_REGEX = r"bafybei[A-Za-z0-9]{52}" PYTHON_LINE_COMMENT_REGEX = r"^#.*\n" -DOC_ELLIPSIS_REGEX = r"\s*#\s...\n" +DOC_ELLIPSIS_REGEX = r"(\s*#\s*...\s*?\n)|(\s*#\s*\(...\)\s*?\n)" +YAML_HASH_REGEX = rf":{IPFS_HASH_REGEX}" PYTHON_COMMAND = r"^pyt(hon|est) (?P.*\.py).*$" MAKE_COMMAND = r"^make (?P.*)$" AUTONOMY_COMMAND = r"^(?Pautonomy .*)$" @@ -84,6 +87,37 @@ def read_file(filepath: str) -> str: return file_str +def read_file_from_repository(url: str) -> str: + """Loads the latest release version of a file into a string""" + match = re.match(r"https://github.com/([^/]+)/([^/]+)/blob/([^/]+)/(.+)", url) + if not match: + raise ValueError("Invalid GitHub file URL") + + owner, repo, _, file_path = match.groups() + + repo_api_url = f"https://api.github.com/repos/{owner}/{repo}/releases/latest" + response = requests.get(repo_api_url) + + if response.status_code == 200: + release_info = response.json() + latest_release_tag = release_info["tag_name"] + raw_github_url = f"https://raw.githubusercontent.com/{owner}/{repo}/{latest_release_tag}/{file_path}" + return read_file_from_url(raw_github_url) + else: + raise Exception( + f"Failed to fetch release information from GitHub API for {owner}/{repo}: {response.text}." + ) + + +def read_file_from_url(url: str) -> str: + """Loads a file into a string""" + response = requests.get(url) + if response.status_code == 200: + return response.text + else: + raise Exception(f"Failed to fetch data from URL {url}: {response.text}.") + + def remove_line_comments(string: str) -> str: """Removes tokens from a python string""" return re.sub(PYTHON_LINE_COMMENT_REGEX, "", string) @@ -94,6 +128,11 @@ def remove_doc_ellipsis(string: str) -> str: return re.sub(DOC_ELLIPSIS_REGEX, "", string) +def remove_yaml_hashes(string: str) -> str: + """Removes YAML ":bafybei..." hashes after a public ID""" + return re.sub(YAML_HASH_REGEX, "", string) + + def remove_ips_hashes(string: str) -> str: """Replaces IPFS hashes with a placeholder""" return re.sub(IPFS_HASH_REGEX, "", string) @@ -145,8 +184,14 @@ def check_code_blocks_exist( code_file = code_file.replace("by_line::", "") # Load the code file and process it - code_path = os.path.join(ROOT_DIR, code_file) - code = read_file(code_path) + if code_file.startswith("https://github.com/"): + code = read_file_from_repository(code_file) + elif code_file.startswith("http://") or code_file.startswith("https://"): + code = read_file_from_url(code_file) + else: + code_path = os.path.join(ROOT_DIR, code_file) + code = read_file(code_path) + code = code_process_fn(code) if code_process_fn else code # Perform the check @@ -186,7 +231,6 @@ def check_bash_commands_exist(md_file: str, make_commands: List[str]) -> None: for code_block in code_blocks: for line in code_block.split("\n"): - # Python/pytest commands match = re.match(PYTHON_COMMAND, line) if match: diff --git a/tests/test_docs/test_code_blocks.py b/tests/test_docs/test_code_blocks.py index 10a9c3f948..ff0e44e237 100644 --- a/tests/test_docs/test_code_blocks.py +++ b/tests/test_docs/test_code_blocks.py @@ -31,6 +31,7 @@ extract_make_commands, remove_doc_ellipsis, remove_line_comments, + remove_yaml_hashes, ) @@ -40,6 +41,8 @@ class BaseTestDocCode: md_to_code: Dict[str, Dict] = {} code_type: CodeType = CodeType.NOCODE skipped_files: Optional[List[str]] = None + doc_process_fn: Optional[Callable] = None + code_process_fn: Optional[Callable] = None def _to_os_path(self, file_path: str) -> str: r""" @@ -106,14 +109,26 @@ def test_run_check(self) -> None: end="", ) - # Preprocessing functions: - # - For doc files: `doc_process_fn` -> remove tokens like "# ...\n" from the code - # - For code files: code_process_fn` not required. + # Eliminate the "self" dependency of the lambda functions. + # This assignment cannot be condensed using the "if" ternary operator. + doc_process_fn = None + if self.doc_process_fn is not None: + + def doc_process_fn(s): # type: ignore + return self.doc_process_fn(s) + + code_process_fn = None + if self.code_process_fn is not None: + + def code_process_fn(s): # type: ignore + return self.code_process_fn(s) + check_code_blocks_exist( md_file=md_file, code_info=code_info, code_type=self.code_type, - doc_process_fn=lambda s: remove_doc_ellipsis(remove_line_comments(s)), + doc_process_fn=doc_process_fn, + code_process_fn=code_process_fn, ) print("OK") @@ -124,6 +139,17 @@ class TestYamlSnippets(BaseTestDocCode): code_type = CodeType.YAML + # Preprocessing function: + # - For Yaml snippets: `doc_process_fn` -> remove tokens like "# (...)\n" from the code + # - For Yaml snippets: `code_process_fn` -> remove ":bafybei..." hashes after component ID + def doc_process_fn(self, s): # type: ignore + """Doc preprocessing function""" + return remove_doc_ellipsis(remove_line_comments(s)) + + def code_process_fn(self, s): # type: ignore + """Code preprocessing function""" + return remove_yaml_hashes(s) + # This variable holds a mapping between every doc file and the code files # that contains the referenced code. Since a doc file can contain several code # snippets, a list with the target files ordered is provided. @@ -134,25 +160,13 @@ class TestYamlSnippets(BaseTestDocCode): # instead of checking the code block as a whole. md_to_code = { - "docs/demos/hello_world_demo.md": { - "code_files": [ - "packages/valory/skills/hello_world_abci/fsm_specification.yaml", - "packages/valory/agents/hello_world/aea-config.yaml", - ], - }, - "docs/demos/price_oracle_fsms.md": { - "code_files": [ - "packages/valory/skills/registration_abci/fsm_specification.yaml", - ], - "skip_blocks": [1, 2, 3, 4, 5], - }, "docs/guides/deploy_service.md": {"skip_blocks": [0]}, "docs/advanced_reference/developer_tooling/benchmarking.md": { "skip_blocks": [0] }, "docs/guides/draft_service_idea_and_define_fsm_specification.md": { "code_files": [ - "packages/valory/skills/hello_world_abci/fsm_specification.yaml" + "https://raw.githubusercontent.com/valory-xyz/hello-world/main/packages/valory/skills/hello_world_abci/fsm_specification.yaml" ] }, } @@ -172,6 +186,12 @@ class TestPythonSnippets(BaseTestDocCode): code_type = CodeType.PYTHON + # Preprocessing function: + # - For Python snippets: `doc_process_fn` -> remove tokens like "# (...)\n" from the code + def doc_process_fn(self, s): # type: ignore + """Doc preprocessing function""" + return remove_doc_ellipsis(remove_line_comments(s)) + # This variable holds a mapping between every doc file and the code file # that contains the referenced code. Since a doc file can contain several code # snippets, a list with the target files ordered is provided. @@ -193,15 +213,6 @@ class TestPythonSnippets(BaseTestDocCode): ], "skip_blocks": [1], }, - "docs/demos/hello_world_demo.md": { - "code_files": [ - "packages/valory/skills/hello_world_abci/behaviours.py", - "packages/valory/skills/hello_world_abci/behaviours.py", - "packages/valory/skills/hello_world_abci/payloads.py", - "packages/valory/skills/hello_world_abci/rounds.py", - "by_line::packages/valory/skills/hello_world_abci/rounds.py", - ], - }, "docs/advanced_reference/commands/autonomy_analyse.md": {"skip_blocks": [0]}, "docs/key_concepts/aea.md": {"code_files": [], "skip_blocks": [0, 1]}, } @@ -232,11 +243,11 @@ class TestJsonSnippets(BaseTestDocCode): # instead of checking the code block as a whole. md_to_code = { - "docs/guides/set_up.md": { - "code_files": ["by_line::packages/packages.json"], - }, "docs/guides/deploy_service.md": { - "code_files": ["by_line::deployments/keys/hardhat_keys.json"], + "code_files": [ + "by_line::deployments/keys/hardhat_keys.json", + "by_line::deployments/keys/hardhat_keys.json", + ], }, "docs/guides/quick_start.md": { "code_files": ["by_line::deployments/keys/hardhat_keys.json"], @@ -249,7 +260,10 @@ class TestJsonSnippets(BaseTestDocCode): }, } - skipped_files = [] + skipped_files = [ + "docs/advanced_reference/commands/autonomy_deploy.md", + "docs/guides/set_up.md", + ] class TestDocBashSnippets: diff --git a/tests/test_docs/test_commands.py b/tests/test_docs/test_commands.py index 7e2d2f6e82..3643f2d757 100644 --- a/tests/test_docs/test_commands.py +++ b/tests/test_docs/test_commands.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- # ------------------------------------------------------------------------------ # -# Copyright 2022 Valory AG +# Copyright 2022-2023 Valory AG # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -55,9 +55,7 @@ def get_group_tree(cmd: Union[click.Group, click.Command]) -> Dict: ctx = click.Context(command=cmd) if isinstance(cmd, click.Group): - for sub_cmd_name in cast(click.Group, cmd).list_commands(ctx=ctx): - # Get the sub-command sub_cmd = cast(click.Command, cmd.get_command(ctx, sub_cmd_name)) @@ -93,7 +91,6 @@ def validate(self, cmd: str, file_: str = "") -> bool: # Iterate the command parts for cmd_part in cmd_parts: - # Subcommands if cmd_part in tree["commands"].keys(): latest_subcmd = cmd_part @@ -154,8 +151,11 @@ def test_validate_doc_commands() -> None: skips = [ "autonomy tests/ --cov", + "aea -- /bin/sh", + "autonomy deploy --env-file COMMAND", + "autonomy deploy --env-file COMMAND", + "aea init --reset --remote --ipfs --author ${AUTHOR}", ] - # Validate all matches for file_ in target_files: if file_.name == "upgrading.md": diff --git a/tox.ini b/tox.ini index fff4ec4b5f..bff5af3ffa 100644 --- a/tox.ini +++ b/tox.ini @@ -6,43 +6,72 @@ ; we set the associated flag (e.g. for linting we don't need ; the package installation). [tox] -envlist = bandit, safety, black, black-check, isort, isort-check, check-copyright, check-hash, check-packages, check-pipfiles, check-api-docs, docs, check-doc-links-hashes, flake8, mypy, pylint, darglint, vulture, check-generate-all-protocols, generate-all-protocols, check-abciapp-specs, check-abci-docstrings, check-handlers, py{3.7,3.8,3.9,3.10}-{win,linux,darwin} +envlist = bandit, safety, black, black-check, isort, isort-check, check-copyright, check-hash, check-packages, check-dependencies, check-api-docs, docs, check-doc-links-hashes, flake8, mypy, pylint, darglint, vulture, check-generate-all-protocols, generate-all-protocols, check-abciapp-specs, check-abci-docstrings, check-handlers, py{3.8,3.9,3.10,3.11}-{win,linux,darwin} ; when running locally we don't want to fail for no good reason skip_missing_interpreters = true [deps-framework] deps = - docker==6.0.0 - docker-compose==1.29.2 + docker==6.1.2 + valory-docker-compose==1.29.3 Flask==2.0.2 - open-aea[all]==1.32.0 - open-aea-cli-ipfs==1.32.0 - open-aea-ledger-ethereum==1.32.0 - open-aea-ledger-ethereum-hwi==1.32.0 + open-aea[all]==1.43.0.post2 + open-aea-cli-ipfs==1.43.0.post2 + open-aea-ledger-ethereum==1.43.0.post2 + open-aea-ledger-ethereum-hwi==1.43.0.post2 Werkzeug==2.0.3 + requests==2.28.1 + texttable==1.6.7 + python-dotenv>=0.14.0,<0.18.0 [deps-tests] deps = {[deps-framework]deps} - tomte[tests]==0.2.4 + tomte[tests]==0.2.15 [deps-packages] deps = {[deps-tests]deps} - aiohttp==3.7.4.post0 - asn1crypto==1.4.0 - cosmpy==0.3.1 - grpcio==1.43.0 + aiohttp<4.0.0,>=3.8.5 + asn1crypto<1.5.0,>=1.4.0 + ecdsa>=0.15 + web3<7,>=6.0.0 + certifi + multidict + eth_typing + eth-account>=0.8.0,<0.9.0 + typing_extensions>=3.10.0.2 + hexbytes + packaging + pytest-asyncio + open-aea-ledger-cosmos==1.43.0.post2 + open-aea-cosmpy==0.6.7 + grpcio==1.53.0 hypothesis==6.21.6 - numpy==1.21.6 - open-aea-ledger-cosmos==1.32.0 - pandas==1.3.5 - pandas-stubs==1.2.0.62 - protobuf>=3.20,<=3.20.1 + protobuf<4.25.0,>=4.21.6 pytz==2022.2.1 - py-ecc==5.2.0 - py-eth-sig-utils==0.4.0 - typing_extensions==3.10.0.2 + py-ecc==6.0.0 + python-dotenv>=0.14.0,<0.18.0 + requests==2.28.1 + tomte[tests,cli]==0.2.15 + texttable==1.6.7 + toml==0.10.2 + eth-utils==2.2.0 + eth-abi==4.0.0 + pycryptodome==3.18.0 + jsonschema<4.4.0,>=4.3.0 + docker==6.1.2 + Flask==2.0.2 + open-aea[all]==1.43.0.post2 + open-aea-ledger-ethereum==1.43.0.post2 + open-aea-ledger-ethereum-hwi==1.43.0.post2 + open-aea-cli-ipfs==1.43.0.post2 + ipfshttpclient==0.8.0a2 + Werkzeug==2.0.3 + watchdog>=2.1.6 + pytest==7.2.1 + click==8.0.2 + valory-docker-compose==1.29.3 [deps-base] deps ={[deps-packages]deps} @@ -106,28 +135,18 @@ commands = aea test --cov --append by-path packages/valory/skills/abstract_round_abci aea test --cov --append by-path packages/valory/skills/counter aea test --cov --append by-path packages/valory/skills/counter_client - aea test --cov --append by-path packages/valory/skills/hello_world_abci aea test --cov --append by-path packages/valory/skills/register_reset_abci aea test --cov --append by-path packages/valory/skills/register_reset_recovery_abci aea test --cov --append by-path packages/valory/skills/register_termination_abci aea test --cov --append by-path packages/valory/skills/registration_abci aea test --cov --append by-path packages/valory/skills/reset_pause_abci + aea test --cov --append by-path packages/valory/skills/slashing_abci + aea test --cov --append by-path packages/valory/skills/offend_abci + aea test --cov --append by-path packages/valory/skills/offend_slash_abci aea test --cov --append by-path packages/valory/skills/termination_abci aea test --cov --append by-path packages/valory/skills/test_abci aea test --cov --append by-path packages/valory/skills/transaction_settlement_abci -[testenv:py3.7-linux] -basepython = python3.7 -platform=^linux$ -deps = {[testenv-multi-ubuntu]deps} -commands = {[commands-framework]commands} - -[testenv:packages-py3.7-linux] -basepython = python3.7 -platform=^linux$ -deps = {[testenv-multi-ubuntu]deps} -commands = {[commands-packages]commands} - [testenv:py3.8-linux] basepython = python3.8 platform=^linux$ @@ -170,16 +189,16 @@ platform=^linux$ deps = {[testenv-multi-ubuntu]deps} commands = {[commands-packages]commands} -[testenv:py3.7-win] -basepython = python3.7 -platform=^win32$ -deps = {[testenv-multi-win]deps} +[testenv:py3.11-linux] +basepython = python3.11 +platform=^linux$ +deps = {[testenv-multi-ubuntu]deps} commands = {[commands-framework]commands} -[testenv:packages-py3.7-win] -basepython = python3.7 -platform=^win32$ -deps = {[testenv-multi-win]deps} +[testenv:packages-py3.11-linux] +basepython = python3.11 +platform=^linux$ +deps = {[testenv-multi-ubuntu]deps} commands = {[commands-packages]commands} [testenv:py3.8-win] @@ -218,16 +237,16 @@ platform=^win32$ deps = {[testenv-multi-win]deps} commands = {[commands-packages]commands} -[testenv:py3.7-darwin] -basepython = python3.7 -platform=^darwin$ -deps = {[testenv-multi-darwin]deps} +[testenv:py3.11-win] +basepython = python3.11 +platform=^win32$ +deps = {[testenv-multi-win]deps} commands = {[commands-framework]commands} -[testenv:packages-py3.7-darwin] -basepython = python3.7 -platform=^darwin$ -deps = {[testenv-multi-darwin]deps} +[testenv:packages-py3.11-win] +basepython = python3.11 +platform=^win32$ +deps = {[testenv-multi-win]deps} commands = {[commands-packages]commands} [testenv:py3.8-darwin] @@ -266,11 +285,23 @@ platform=^darwin$ deps = {[testenv-multi-darwin]deps} commands = {[commands-packages]commands} +[testenv:py3.11-darwin] +basepython = python3.11 +platform=^darwin$ +deps = {[testenv-multi-darwin]deps} +commands = {[commands-framework]commands} + +[testenv:packages-py3.11-darwin] +basepython = python3.11 +platform=^darwin$ +deps = {[testenv-multi-darwin]deps} +commands = {[commands-packages]commands} + [testenv:bandit] skipsdist = True skip_install = True deps = - tomte[bandit]==0.2.4 + tomte[bandit]==0.2.15 commands = bandit -r autonomy plugins -x */tests/* bandit -s B101 -r packages/valory @@ -280,7 +311,7 @@ commands = skipsdist = True skip_install = True deps = - tomte[black]==0.2.4 + tomte[black]==0.2.15 commands = black autonomy packages/valory scripts tests deployments plugins @@ -288,7 +319,7 @@ commands = skipsdist = True skip_install = True deps = - tomte[black]==0.2.4 + tomte[black]==0.2.15 commands = black --check autonomy packages/valory scripts tests deployments plugins @@ -296,7 +327,7 @@ commands = skipsdist = True skip_install = True deps = - tomte[isort]==0.2.4 + tomte[isort]==0.2.15 commands = isort autonomy/ isort packages/valory --gitignore @@ -309,7 +340,7 @@ commands = skipsdist = True skip_install = True deps = - tomte[isort]==0.2.4 + tomte[isort]==0.2.15 commands = isort --check-only --gitignore autonomy packages/valory scripts tests plugins @@ -354,22 +385,25 @@ deps = {[deps-packages]deps} commands = python -m pip install --no-deps file://{toxinidir}/plugins/aea-test-autonomy - autonomy hash all autonomy packages lock + python scripts/check_doc_ipfs_hashes.py --fix + python scripts/generate_package_list.py -[testenv:check-pipfiles] +[testenv:check-dependencies] skipsdist = True usedevelop = True deps = + {[deps-packages]deps} commands = - {toxinidir}/scripts/check_pipfiles.py + autonomy packages sync + {toxinidir}/scripts/check_dependencies.py [testenv:check-api-docs] skipsdist = True skip_install = True deps = {[deps-packages]deps} - tomte[docs]==0.2.4 + tomte[docs]==0.2.15 commands = {toxinidir}/scripts/generate_api_documentation.py --check-clean @@ -378,7 +412,7 @@ skipsdist = True skip_install = True deps = {[deps-packages]deps} - tomte[docs]==0.2.4 + tomte[docs]==0.2.15 commands = {toxinidir}/scripts/generate_api_documentation.py @@ -403,19 +437,21 @@ commands = skipsdist = True skip_install = True deps = - tomte[docs]==0.2.4 + tomte[docs]==0.2.15 mkdocs-redirects commands = - mkdocs build --clean --strict + ; TODO: Add --strict flag after fixing the material dependency + mkdocs build --clean [testenv:docs-serve] skipsdist = True skip_install = True deps = - tomte[docs]==0.2.4 + tomte[docs]==0.2.15 mkdocs-redirects commands = - mkdocs build --clean --strict + ; TODO: Add --strict flag after fixing the material dependency + mkdocs build --clean python -c 'print("###### Starting local server. Press Control+C to stop server ######")' mkdocs serve -a localhost:8080 @@ -423,7 +459,7 @@ commands = skipsdist = True skip_install = True deps = - tomte[flake8]==0.2.4 + tomte[flake8]==0.2.15 commands = flake8 autonomy packages/valory scripts tests deployments plugins @@ -431,28 +467,28 @@ commands = skipsdist = True skip_install = True deps = - tomte[mypy]==0.2.4 + tomte[mypy]==0.2.15 commands = python -m pip install --no-deps file://{toxinidir}/plugins/aea-test-autonomy - mypy autonomy packages/valory plugins/aea-test-autonomy/aea_test_autonomy tests scripts --disallow-untyped-defs - mypy plugins/aea-test-autonomy/tests --disallow-untyped-defs + mypy autonomy packages/valory plugins/aea-test-autonomy/aea_test_autonomy tests scripts --disallow-untyped-defs --config-file tox.ini + mypy plugins/aea-test-autonomy/tests --disallow-untyped-defs --config-file tox.ini [testenv:pylint] whitelist_externals = /bin/sh skipsdist = True deps = {[deps-packages]deps} - tomte[pylint]==0.2.4 + tomte[pylint]==0.2.15 commands = python -m pip install --no-deps file://{toxinidir}/plugins/aea-test-autonomy - pylint --rcfile=setup.cfg autonomy packages/valory scripts deployments plugins -j 0 + pylint --rcfile=.pylintrc autonomy packages/valory scripts deployments plugins -j 0 # -j0 to utilize all cpu cores [testenv:safety] skipsdist = True skip_install = True deps = - tomte[safety]==0.2.4 + tomte[safety]==0.2.15 commands = safety check -i 37524 -i 38038 -i 37776 -i 38039 -i 39621 -i 40291 -i 39706 -i 41002 -i 51358 -i 51499 @@ -460,15 +496,15 @@ commands = skipsdist = True skip_install = True deps = - tomte[vulture]==0.2.4 + tomte[vulture]==0.2.15 commands = - vulture autonomy scripts/whitelist.py + vulture autonomy/services scripts/whitelist.py [testenv:darglint] skipsdist = True skip_install = True deps = - tomte[darglint]==0.2.4 + tomte[darglint]==0.2.15 commands = darglint autonomy scripts packages/valory/* tests deployments plugins @@ -477,8 +513,8 @@ skipsdist = True usedevelop = True deps = {[deps-packages]deps} - tomte[isort]==0.2.4 - tomte[black]==0.2.4 + tomte[isort]==0.2.15 + tomte[black]==0.2.15 commands = aea generate-all-protocols --check-clean @@ -487,8 +523,8 @@ skipsdist = True usedevelop = True deps = {[deps-packages]deps} - tomte[isort]==0.2.4 - tomte[black]==0.2.4 + tomte[isort]==0.2.15 + tomte[black]==0.2.15 commands = aea generate-all-protocols @@ -496,9 +532,8 @@ commands = whitelist_externals = mdspell skipsdist = True usedevelop = True -deps = -commands = - {toxinidir}/scripts/spell-check.sh +deps = tomte[cli]==0.2.15 +commands = tomte check-spelling [testenv:abci-docstrings] skipsdist = True @@ -524,18 +559,385 @@ commands = skipsdist = True usedevelop = True commands = - autonomy analyse handlers -h abci -h http -h contract_api -h ledger_api -h signing -i abstract_abci -i counter -i counter_client -i hello_world_abci + autonomy analyse handlers -h abci -h http -h contract_api -h ledger_api -h signing -i abstract_abci -i counter -i counter_client [testenv:check-dialogues] skipsdist = True usedevelop = True commands = - autonomy analyse dialogues -d abci -d http -d contract_api -d ledger_api -d signing -i abstract_abci -i counter -i counter_client -i hello_world_abci + autonomy analyse dialogues -d abci -d http -d contract_api -d ledger_api -d signing -i abstract_abci -i counter -i counter_client + [testenv:liccheck] skipsdist = True usedevelop = True -deps = - tomte[liccheck]==0.2.4 -commands = {toxinidir}/scripts/freeze_dependencies.py -o {envtmpdir}/requirements.txt - liccheck -s liccheck.ini -r {envtmpdir}/requirements.txt -l PARANOID \ No newline at end of file +deps = tomte[liccheck,cli]==0.2.15 +commands = + tomte freeze-dependencies --output-path {envtmpdir}/requirements.txt + liccheck -s tox.ini -r {envtmpdir}/requirements.txt -l PARANOID + +[pytest] +log_cli = 1 +log_cli_level = DEBUG +log_cli_format = %(asctime)s [%(levelname)8s] %(message)s (%(filename)s:%(lineno)s) +log_cli_date_format=%Y-%m-%d %H:%M:%S + +markers = + integration: marks integration tests which require other network services + e2e: marks end-to-end agent tests + + +filterwarnings = + ignore::DeprecationWarning:aea.*: + ignore::DeprecationWarning + ignore:.*MismatchedABI + ignore:.*cannot collect test class 'TestAbciApp' + ignore:.*cannot collect test class 'TestAbciConsensusBehaviour' + +[flake8] +paths=autonomy,packages,scripts,tests +exclude=.md, + *_pb2.py, + autonomy/__init__.py, + custom_types.py, + *_pb2_grpc.py, + packages/valory/connections/http_client, + packages/valory/connections/ledger, + packages/valory/connections/p2p_libp2p_client, + packages/valory/protocols/acn, + packages/valory/protocols/contract_api, + packages/valory/protocols/http, + packages/valory/protocols/ledger_api +max-line-length = 88 +select = B,C,D,E,F,I,W, +ignore = E203,E501,W503,D202,B014,D400,D401,DAR,B028,B017 +application-import-names = autonomy,packages,tests,scripts + +# ignore as too restrictive for our needs: +# D400: First line should end with a period +# D401: First line should be in imperative mood +# E501: https://www.flake8rules.com/rules/E501.html (Line too long) +# E203: https://www.flake8rules.com/rules/E203.html (Whitespace) +# W503: https://www.flake8rules.com/rules/W503.html (Line break) +# D202: blank lines +# B014: redundant exception + +[isort] +# for black compatibility +multi_line_output=3 +include_trailing_comma=True +force_grid_wrap=0 +use_parentheses=True +ensure_newline_before_comments = True +line_length=88 +# custom configurations +order_by_type=False +case_sensitive=True +lines_after_imports=2 +skip = +skip_glob = +known_first_party=autonomy +known_packages=packages +known_local_folder=tests +sections=FUTURE,STDLIB,THIRDPARTY,FIRSTPARTY,PACKAGES,LOCALFOLDER + +[mypy] +python_version = 3.10 +strict_optional = True +exclude=(.*_pb2|.*custom_types|packages/valory/connections/abci/tendermint/abci/|autonomy/data/Dockerfiles|packages/valory/connections/http_client|packages/valory/connections/ledger|packages/valory/connections/p2p_libp2p_client|packages/valory/protocols/acn|packages/valory/protocols/contract_api|packages/valory/protocols/http|packages/valory/protocols/ledger_api|packages/valory/protocols/abci|packages/valory/protocols/tendermint|packages/valory/protocols/ipfs) + +# Before adding a module here, make sure it does not support type hints + +# Per-module options for aea dir: + +[mypy-aea.*] +ignore_missing_imports = True + +[mypy-google.*] +ignore_missing_imports = True + +[mypy-ipfshttpclient.*] +ignore_missing_imports = True + +# Per-module options for examples dir: + +# Per-module options for tests dir: + +[mypy-pytest] +ignore_missing_imports = True + +[mypy-docker.*] +ignore_missing_imports = True + +[mypy-hypothesis.*] +ignore_missing_imports = True + +# Per-module options for packages dir: + +[mypy-eth_keys.*] +ignore_errors=True + +[mypy-eth_account.*] +ignore_missing_imports=True + +[mypy-eth_abi.*] +ignore_missing_imports = True + +[mypy-packages.valory.protocols.abci.custom_types] +ignore_errors=True + +[mypy-packages.valory.protocols.abci.abci_pb2] +ignore_errors=True + +[mypy-packages.valory.protocols.ledger_api.ledger_api_pb2] +ignore_errors=True + +[mypy-packages.valory.protocols.contract_api.contract_api_pb2] +ignore_errors=True + +[mypy-packages.valory.protocols.http.http_pb2] +ignore_errors=True + +[mypy-packages.open_aea.protocols.signing.signing_pb2] +ignore_errors=True + +[mypy-packages.valory.connections.abci.tendermint.types.*] +ignore_errors=True + +[mypy-packages.valory.connections.abci.tendermint.types.types_pb2] +ignore_errors=True + +[mypy-packages.valory.connections.abci.tendermint.abci.types_pb2] +ignore_errors=True + +[mypy-packages.valory.connections.abci.tendermint.abci.types_pb2_grpc] +ignore_errors=True + +[mypy-autonomy.data.Dockerfiles.tendermint.tendermint] +ignore_missing_imports = True + +[mypy-packages.valory.protocols.acn.acn_pb2] +ignore_errors = True + +[mypy-packages.valory.protocols.tendermint.tendermint_pb2] +ignore_errors = True + +[mypy-typed-ast.*] +ignore_missing_imports = True + +[mypy-py_eth_sig_utils.*] +ignore_missing_imports = True + +[mypy-aiohttp.*] +ignore_missing_imports = True + +[mypy-multidict.*] +ignore_missing_imports = True + +[mypy-certifi.*] +ignore_missing_imports = True + +[mypy-eth_typing.*] +ignore_missing_imports = True + +[mypy-packaging.*] +ignore_missing_imports = True + +[mypy-hexbytes.*] +ignore_missing_imports = True + +[mypy-web3.*] +ignore_missing_imports = True + +[mypy-_pytest.*] +ignore_missing_imports = True + +[mypy-aea_ledger_ethereum.*] +ignore_missing_imports = True + +[mypy-aea_ledger_ethereum_hwi.*] +ignore_missing_imports = True + +[mypy-google.protobuf.*] +ignore_missing_imports=True + +[mypy-requests.*] +ignore_missing_imports=True + +[mypy-yaml] +ignore_missing_imports=True + +[mypy-toml] +ignore_missing_imports=True + +[mypy-jsonschema.*] +ignore_missing_imports=True + +[mypy-pkg_resources] +ignore_missing_imports=True + +# Per-module options for scripts dir: + +[mypy-click.*] +ignore_missing_imports = True + +[mypy-semver.*] +ignore_missing_imports = True + +[mypy-scripts.common.*] +ignore_missing_imports = True + +[mypy-aea_cli_ipfs.*] +ignore_missing_imports = True + +[mypy-watchdog.*] +ignore_missing_imports = True + +[mypy-flask.*] +ignore_missing_imports = True + +[mypy-werkzeug.*] +ignore_missing_imports = True + +[mypy-compose.*] +ignore_missing_imports = True + +[mypy-_strptime.*] +ignore_missing_imports = True + +[mypy-pytz.*] +ignore_missing_imports = True + +[mypy-py_ecc.*] +ignore_missing_imports = True + +[mypy-grpc.*] +ignore_missing_imports = True + +[mypy-pytest_asyncio.*] +ignore_missing_imports = True + +[mypy-texttable.*] +ignore_missing_imports = True + +[mypy-dotenv.*] +ignore_missing_imports = True + +[mypy-Crypto.*] +ignore_missing_imports = True + +[mypy-eth_utils.*] +ignore_missing_imports = True + +[darglint] +docstring_style=sphinx +strictness=short +ignore_regex=async_act +ignore=DAR401 + +; some useful links: +; - https://janelia-flyem.github.io/licenses.html +; - https://dwheeler.com/essays/floss-license-slide.html + +; Authorized and unauthorized licenses in LOWER CASE +[Licenses] +authorized_licenses: + ; aliases for MIT License + MIT + MIT license + https://opensource.org/licenses/MIT + License :: OSI Approved :: MIT + + ; aliases for BSD License (and variants) + BSD + BSD license + new BSD + (new) BSD + new BDS license + simplified BSD + 3-Clause BSD + BSD-3-Clause + BSD 3-Clause + BSD-2-Clause + BSD-like + BSD-2-Clause or Apache-2.0 + BSD, Public Domain + + ; Apache + Apache Software + + ; aliases for Apache License version 2.0 + Apache 2.0 + Apache-2.0 + Apache License 2.0 + Apache License, Version 2.0 + Apache License Version 2.0 + Apache2 + ASL 2 +; some packages use 'Apache Software' as license string, +; which is ambiguous. However, 'Apache Software' +; will likely match with 'Apache 2.0' + Apache Software + BSD, Public Domain, Apache + http://www.apache.org/licenses/LICENSE-2.0 + +; PSF (BSD-style) + Python Software Foundation + PSF + + ; other permissive licenses + Historical Permission Notice and Disclaimer (HPND) + HPND + ISC + BSD or Apache License, Version 2.0 + Modified BSD + Expat + Public Domain + +unauthorized_licenses: +; aliases for MPL 2.0 + MPL-2.0 + MPL 2.0 + Mozilla Public License 2.0 (MPL 2.0) + +; Section 8 of https://www.mozilla.org/en-US/MPL/2.0/Revision-FAQ/ + MPL 1.1 + MPL-1.1 + +; http://www.gnu.org/licenses/license-list.en.html#apache2 + GPLv2 + GPLv2+ + GNU General Public License v2 or later (GPLv2+) + +; LGPL + LGPL + GNU Library or Lesser General Public License (LGPL) + +; LGPLv2.1 + LGPLv2.1 + LGPLv2.1+ + GNU Lesser General Public License v2 or later (LGPLv2+) + +; LGPLv3 + GNU Lesser General Public License v3 (LGPLv3) + LGPLv3 + +; GPL v3 + GPL v3 + GPLv3+ + GNU General Public License v3 (GPLv3) + +[Authorized Packages] +gym: >=0.15 +;filelock is public domain +filelock: >=3.0.12 +fetchai-ledger-api: >=0.0.1 +chardet: >=3.0.4 +certifi: >=2019.11.28 +;TODO: the following are confilctive packages that need to be sorted +; sub-dep of open-aea-ledger-ethereum-hwi +hidapi: >=0.13.1 +; shows in pip freesze but not referenced on code +paramiko: >=3.1.0 +; sub-dep of docker-compose +websocket-client: >=0.59.0