diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index bb8ace29..955d49eb 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -4,7 +4,7 @@ on: push: branches: "**" pull_request: - branches: ["main"] + branches: ["main", "chang"] types: [opened, reopened, edited, synchronize] jobs: @@ -14,7 +14,7 @@ jobs: strategy: matrix: os: [ubuntu-latest, macos-latest] - python-version: [3.8, 3.9, '3.10', '3.11'] + python-version: ['3.8', '3.9', '3.10', '3.11'] steps: - uses: actions/checkout@v4 @@ -59,18 +59,30 @@ jobs: python-version: ${{ matrix.python-version }} cache: 'poetry' + - name: Setup docker-compose + uses: KengoTODA/actions-setup-docker-compose@v1.2.2 + with: + version: '2.14.2' + - name: Run integration tests run: | cd integration-test && ./run_tests.sh + - name: "Upload coverage to Codecov" + if: ${{ matrix.python-version == '3.11' }} + uses: codecov/codecov-action@v4 + with: + fail_ci_if_error: true + token: ${{ secrets.CODECOV_TOKEN }} + - name: Dump docker logs if: failure() run: | - cd integration-test && docker-compose logs --no-color > integration-test.log + cd integration-test && docker compose logs --no-color > integration-test.log - name: Upload integration-test.log if: failure() - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v4 with: name: integration-test.log path: integration-test/integration-test.log \ No newline at end of file diff --git a/.gitignore b/.gitignore index b5e58dea..c14a0292 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,8 @@ cov_html docs/build dist +.mypy_cache +coverage.xml # IDE .idea diff --git a/docs/requirements.txt b/docs/requirements.txt index 22ce70ae..980587a1 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -1,35 +1,39 @@ alabaster==0.7.13 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" +annotated-types==0.7.0 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" asn1crypto==1.5.1 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" -attrs==23.2.0 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" -babel==2.15.0 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" -black==24.4.2 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" +attrs==24.2.0 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" +babel==2.16.0 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" +black==24.8.0 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" blinker==1.8.2 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" blockfrost-python==0.5.3 ; python_full_version >= "3.8.1" and python_version < "4" -cachetools==5.3.3 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" -cbor2==5.6.3 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" -certifi==2024.2.2 ; python_full_version >= "3.8.1" and python_version < "4" +cachetools==5.5.0 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" +cardano-tools==2.1.0 ; python_full_version >= "3.8.1" and python_version < "4.0" +cbor2==5.6.4 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" +certifi==2024.8.30 ; python_full_version >= "3.8.1" and python_version < "4" certvalidator==0.11.1 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" -cffi==1.16.0 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" +cffi==1.17.0 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" charset-normalizer==3.3.2 ; python_full_version >= "3.8.1" and python_version < "4" click==8.1.7 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" colorama==0.4.6 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" and (sys_platform == "win32" or platform_system == "Windows") +coloredlogs==15.0.1 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" cose==0.9.dev8 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" -coverage[toml]==7.5.3 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" -cryptography==42.0.7 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" +coverage[toml]==7.6.1 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" +cryptography==43.0.0 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" decorator==5.1.1 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" docker==7.1.0 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" docutils==0.19 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" ecdsa==0.19.0 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" ecpy==1.2.5 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" -exceptiongroup==1.2.1 ; python_full_version >= "3.8.1" and python_version < "3.11" +exceptiongroup==1.2.2 ; python_full_version >= "3.8.1" and python_version < "3.11" execnet==2.1.1 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" -flake8==7.0.0 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" +flake8==7.1.1 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" flask==2.3.3 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" frozendict==2.4.4 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" frozenlist==1.4.1 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" -idna==3.7 ; python_full_version >= "3.8.1" and python_version < "4" +humanfriendly==10.0 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" +idna==3.8 ; python_full_version >= "3.8.1" and python_version < "4" imagesize==1.4.1 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" -importlib-metadata==7.1.0 ; python_full_version >= "3.8.1" and python_version < "3.10" +importlib-metadata==8.4.0 ; python_full_version >= "3.8.1" and python_version < "3.10" iniconfig==2.0.0 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" isort==5.13.2 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" itsdangerous==2.2.0 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" @@ -39,21 +43,28 @@ mccabe==0.7.0 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" mnemonic==0.21 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" mypy-extensions==1.0.0 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" mypy==1.4.1 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" +ogmios @ git+https://gitlab.com/viperscience/ogmios-python.git@0b713e78839341d92828340a5552ef8dd1c6224b ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" +orjson==3.10.7 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" oscrypto==1.3.0 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" -packaging==24.0 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" +packaging==24.1 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" pathspec==0.12.1 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" +pexpect==4.9.0 ; python_full_version >= "3.8.1" and python_version < "4.0" platformdirs==4.2.2 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" pluggy==1.5.0 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" pprintpp==0.4.0 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" +ptyprocess==0.7.0 ; python_full_version >= "3.8.1" and python_version < "4.0" py==1.11.0 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" -pycodestyle==2.11.1 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" +pycodestyle==2.12.1 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" pycparser==2.22 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" +pydantic-core==2.20.1 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" +pydantic==2.8.2 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" pyflakes==3.2.0 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" pygments==2.18.0 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" pynacl==1.5.0 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" +pyreadline3==3.4.1 ; sys_platform == "win32" and python_full_version >= "3.8.1" and python_full_version < "4.0.0" pytest-cov==5.0.0 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" pytest-xdist==3.6.1 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" -pytest==8.2.1 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" +pytest==8.3.2 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" pytz==2024.1 ; python_full_version >= "3.8.1" and python_version < "3.9" pywin32==306 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" and sys_platform == "win32" requests==2.32.3 ; python_full_version >= "3.8.1" and python_version < "4" @@ -74,8 +85,9 @@ sphinxcontrib-serializinghtml==1.1.5 ; python_full_version >= "3.8.1" and python tomli==2.0.1 ; python_full_version >= "3.8.1" and python_full_version <= "3.11.0a6" typeguard==4.3.0 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" types-requests==2.31.0.10 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" -typing-extensions==4.12.0 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" -urllib3==2.2.1 ; python_full_version >= "3.8.1" and python_version < "4" +typing-extensions==4.12.2 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" +urllib3==2.2.2 ; python_full_version >= "3.8.1" and python_version < "4" websocket-client==1.8.0 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" -werkzeug==3.0.3 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" -zipp==3.19.1 ; python_full_version >= "3.8.1" and python_version < "3.10" +websockets==13.0.1 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" +werkzeug==3.0.4 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" +zipp==3.20.1 ; python_full_version >= "3.8.1" and python_version < "3.10" diff --git a/docs/source/api/pycardano.backend.base.rst b/docs/source/api/pycardano.backend.base.rst index 91e70e5f..039007d7 100644 --- a/docs/source/api/pycardano.backend.base.rst +++ b/docs/source/api/pycardano.backend.base.rst @@ -11,7 +11,12 @@ Backend :undoc-members: :show-inheritance: -.. automodule:: pycardano.backend.ogmios +.. automodule:: pycardano.backend.ogmios_v6 + :members: + :undoc-members: + :show-inheritance: + +.. automodule:: pycardano.backend.ogmios_v5 :members: :undoc-members: :show-inheritance: diff --git a/integration-test/bootstrap.sh b/integration-test/bootstrap.sh index 5f7ac89c..60ad8640 100755 --- a/integration-test/bootstrap.sh +++ b/integration-test/bootstrap.sh @@ -20,9 +20,9 @@ NETWORK=$1 echo "Bootstrapping network: $NETWORK" -if [ "$NETWORK" = "local-alonzo" ] || [ "$NETWORK" = "local-vasil" ]; then +if [ "$NETWORK" = "local-alonzo" ] || [ "$NETWORK" = "local-vasil" ] || [ "$NETWORK" = "local-chang" ]; then echo "Updating byron startTime to present in local mode, $NETWORK era" - jq -M ".startTime = ""$(date +%s)" configs/"$NETWORK"/byron-genesis.json > \ + jq -M ".startTime = ($(date +%s) + 60)" configs/"$NETWORK"/byron-genesis.json > \ tmp_configs/"$NETWORK"/byron-genesis.json fi diff --git a/integration-test/configs/local-chang/alonzo-genesis.json b/integration-test/configs/local-chang/alonzo-genesis.json new file mode 100644 index 00000000..643a7810 --- /dev/null +++ b/integration-test/configs/local-chang/alonzo-genesis.json @@ -0,0 +1,365 @@ +{ + "collateralPercentage": 150, + "costModels": { + "PlutusV1": [ + 197209, + 0, + 1, + 1, + 396231, + 621, + 0, + 1, + 150000, + 1000, + 0, + 1, + 150000, + 32, + 2477736, + 29175, + 4, + 29773, + 100, + 29773, + 100, + 29773, + 100, + 29773, + 100, + 29773, + 100, + 29773, + 100, + 100, + 100, + 29773, + 100, + 150000, + 32, + 150000, + 32, + 150000, + 32, + 150000, + 1000, + 0, + 1, + 150000, + 32, + 150000, + 1000, + 0, + 8, + 148000, + 425507, + 118, + 0, + 1, + 1, + 150000, + 1000, + 0, + 8, + 150000, + 112536, + 247, + 1, + 150000, + 10000, + 1, + 136542, + 1326, + 1, + 1000, + 150000, + 1000, + 1, + 150000, + 32, + 150000, + 32, + 150000, + 32, + 1, + 1, + 150000, + 1, + 150000, + 4, + 103599, + 248, + 1, + 103599, + 248, + 1, + 145276, + 1366, + 1, + 179690, + 497, + 1, + 150000, + 32, + 150000, + 32, + 150000, + 32, + 150000, + 32, + 150000, + 32, + 150000, + 32, + 148000, + 425507, + 118, + 0, + 1, + 1, + 61516, + 11218, + 0, + 1, + 150000, + 32, + 148000, + 425507, + 118, + 0, + 1, + 1, + 148000, + 425507, + 118, + 0, + 1, + 1, + 2477736, + 29175, + 4, + 0, + 82363, + 4, + 150000, + 5000, + 0, + 1, + 150000, + 32, + 197209, + 0, + 1, + 1, + 150000, + 32, + 150000, + 32, + 150000, + 32, + 150000, + 32, + 150000, + 32, + 150000, + 32, + 150000, + 32, + 3345831, + 1, + 1 + ], + "PlutusV2": { + "addInteger-cpu-arguments-intercept": 205665, + "addInteger-cpu-arguments-slope": 812, + "addInteger-memory-arguments-intercept": 1, + "addInteger-memory-arguments-slope": 1, + "appendByteString-cpu-arguments-intercept": 1000, + "appendByteString-cpu-arguments-slope": 571, + "appendByteString-memory-arguments-intercept": 0, + "appendByteString-memory-arguments-slope": 1, + "appendString-cpu-arguments-intercept": 1000, + "appendString-cpu-arguments-slope": 24177, + "appendString-memory-arguments-intercept": 4, + "appendString-memory-arguments-slope": 1, + "bData-cpu-arguments": 1000, + "bData-memory-arguments": 32, + "blake2b_256-cpu-arguments-intercept": 117366, + "blake2b_256-cpu-arguments-slope": 10475, + "blake2b_256-memory-arguments": 4, + "cekApplyCost-exBudgetCPU": 23000, + "cekApplyCost-exBudgetMemory": 100, + "cekBuiltinCost-exBudgetCPU": 23000, + "cekBuiltinCost-exBudgetMemory": 100, + "cekConstCost-exBudgetCPU": 23000, + "cekConstCost-exBudgetMemory": 100, + "cekDelayCost-exBudgetCPU": 23000, + "cekDelayCost-exBudgetMemory": 100, + "cekForceCost-exBudgetCPU": 23000, + "cekForceCost-exBudgetMemory": 100, + "cekLamCost-exBudgetCPU": 23000, + "cekLamCost-exBudgetMemory": 100, + "cekStartupCost-exBudgetCPU": 100, + "cekStartupCost-exBudgetMemory": 100, + "cekVarCost-exBudgetCPU": 23000, + "cekVarCost-exBudgetMemory": 100, + "chooseData-cpu-arguments": 19537, + "chooseData-memory-arguments": 32, + "chooseList-cpu-arguments": 175354, + "chooseList-memory-arguments": 32, + "chooseUnit-cpu-arguments": 46417, + "chooseUnit-memory-arguments": 4, + "consByteString-cpu-arguments-intercept": 221973, + "consByteString-cpu-arguments-slope": 511, + "consByteString-memory-arguments-intercept": 0, + "consByteString-memory-arguments-slope": 1, + "constrData-cpu-arguments": 89141, + "constrData-memory-arguments": 32, + "decodeUtf8-cpu-arguments-intercept": 497525, + "decodeUtf8-cpu-arguments-slope": 14068, + "decodeUtf8-memory-arguments-intercept": 4, + "decodeUtf8-memory-arguments-slope": 2, + "divideInteger-cpu-arguments-constant": 196500, + "divideInteger-cpu-arguments-model-arguments-intercept": 453240, + "divideInteger-cpu-arguments-model-arguments-slope": 220, + "divideInteger-memory-arguments-intercept": 0, + "divideInteger-memory-arguments-minimum": 1, + "divideInteger-memory-arguments-slope": 1, + "encodeUtf8-cpu-arguments-intercept": 1000, + "encodeUtf8-cpu-arguments-slope": 28662, + "encodeUtf8-memory-arguments-intercept": 4, + "encodeUtf8-memory-arguments-slope": 2, + "equalsByteString-cpu-arguments-constant": 245000, + "equalsByteString-cpu-arguments-intercept": 216773, + "equalsByteString-cpu-arguments-slope": 62, + "equalsByteString-memory-arguments": 1, + "equalsData-cpu-arguments-intercept": 1060367, + "equalsData-cpu-arguments-slope": 12586, + "equalsData-memory-arguments": 1, + "equalsInteger-cpu-arguments-intercept": 208512, + "equalsInteger-cpu-arguments-slope": 421, + "equalsInteger-memory-arguments": 1, + "equalsString-cpu-arguments-constant": 187000, + "equalsString-cpu-arguments-intercept": 1000, + "equalsString-cpu-arguments-slope": 52998, + "equalsString-memory-arguments": 1, + "fstPair-cpu-arguments": 80436, + "fstPair-memory-arguments": 32, + "headList-cpu-arguments": 43249, + "headList-memory-arguments": 32, + "iData-cpu-arguments": 1000, + "iData-memory-arguments": 32, + "ifThenElse-cpu-arguments": 80556, + "ifThenElse-memory-arguments": 1, + "indexByteString-cpu-arguments": 57667, + "indexByteString-memory-arguments": 4, + "lengthOfByteString-cpu-arguments": 1000, + "lengthOfByteString-memory-arguments": 10, + "lessThanByteString-cpu-arguments-intercept": 197145, + "lessThanByteString-cpu-arguments-slope": 156, + "lessThanByteString-memory-arguments": 1, + "lessThanEqualsByteString-cpu-arguments-intercept": 197145, + "lessThanEqualsByteString-cpu-arguments-slope": 156, + "lessThanEqualsByteString-memory-arguments": 1, + "lessThanEqualsInteger-cpu-arguments-intercept": 204924, + "lessThanEqualsInteger-cpu-arguments-slope": 473, + "lessThanEqualsInteger-memory-arguments": 1, + "lessThanInteger-cpu-arguments-intercept": 208896, + "lessThanInteger-cpu-arguments-slope": 511, + "lessThanInteger-memory-arguments": 1, + "listData-cpu-arguments": 52467, + "listData-memory-arguments": 32, + "mapData-cpu-arguments": 64832, + "mapData-memory-arguments": 32, + "mkCons-cpu-arguments": 65493, + "mkCons-memory-arguments": 32, + "mkNilData-cpu-arguments": 22558, + "mkNilData-memory-arguments": 32, + "mkNilPairData-cpu-arguments": 16563, + "mkNilPairData-memory-arguments": 32, + "mkPairData-cpu-arguments": 76511, + "mkPairData-memory-arguments": 32, + "modInteger-cpu-arguments-constant": 196500, + "modInteger-cpu-arguments-model-arguments-intercept": 453240, + "modInteger-cpu-arguments-model-arguments-slope": 220, + "modInteger-memory-arguments-intercept": 0, + "modInteger-memory-arguments-minimum": 1, + "modInteger-memory-arguments-slope": 1, + "multiplyInteger-cpu-arguments-intercept": 69522, + "multiplyInteger-cpu-arguments-slope": 11687, + "multiplyInteger-memory-arguments-intercept": 0, + "multiplyInteger-memory-arguments-slope": 1, + "nullList-cpu-arguments": 60091, + "nullList-memory-arguments": 32, + "quotientInteger-cpu-arguments-constant": 196500, + "quotientInteger-cpu-arguments-model-arguments-intercept": 453240, + "quotientInteger-cpu-arguments-model-arguments-slope": 220, + "quotientInteger-memory-arguments-intercept": 0, + "quotientInteger-memory-arguments-minimum": 1, + "quotientInteger-memory-arguments-slope": 1, + "remainderInteger-cpu-arguments-constant": 196500, + "remainderInteger-cpu-arguments-model-arguments-intercept": 453240, + "remainderInteger-cpu-arguments-model-arguments-slope": 220, + "remainderInteger-memory-arguments-intercept": 0, + "remainderInteger-memory-arguments-minimum": 1, + "remainderInteger-memory-arguments-slope": 1, + "serialiseData-cpu-arguments-intercept": 1159724, + "serialiseData-cpu-arguments-slope": 392670, + "serialiseData-memory-arguments-intercept": 0, + "serialiseData-memory-arguments-slope": 2, + "sha2_256-cpu-arguments-intercept": 806990, + "sha2_256-cpu-arguments-slope": 30482, + "sha2_256-memory-arguments": 4, + "sha3_256-cpu-arguments-intercept": 1927926, + "sha3_256-cpu-arguments-slope": 82523, + "sha3_256-memory-arguments": 4, + "sliceByteString-cpu-arguments-intercept": 265318, + "sliceByteString-cpu-arguments-slope": 0, + "sliceByteString-memory-arguments-intercept": 4, + "sliceByteString-memory-arguments-slope": 0, + "sndPair-cpu-arguments": 85931, + "sndPair-memory-arguments": 32, + "subtractInteger-cpu-arguments-intercept": 205665, + "subtractInteger-cpu-arguments-slope": 812, + "subtractInteger-memory-arguments-intercept": 1, + "subtractInteger-memory-arguments-slope": 1, + "tailList-cpu-arguments": 41182, + "tailList-memory-arguments": 32, + "trace-cpu-arguments": 212342, + "trace-memory-arguments": 32, + "unBData-cpu-arguments": 31220, + "unBData-memory-arguments": 32, + "unConstrData-cpu-arguments": 32696, + "unConstrData-memory-arguments": 32, + "unIData-cpu-arguments": 43357, + "unIData-memory-arguments": 32, + "unListData-cpu-arguments": 32247, + "unListData-memory-arguments": 32, + "unMapData-cpu-arguments": 38314, + "unMapData-memory-arguments": 32, + "verifyEcdsaSecp256k1Signature-cpu-arguments": 20000000000, + "verifyEcdsaSecp256k1Signature-memory-arguments": 20000000000, + "verifyEd25519Signature-cpu-arguments-intercept": 9462713, + "verifyEd25519Signature-cpu-arguments-slope": 1021, + "verifyEd25519Signature-memory-arguments": 10, + "verifySchnorrSecp256k1Signature-cpu-arguments-intercept": 20000000000, + "verifySchnorrSecp256k1Signature-cpu-arguments-slope": 0, + "verifySchnorrSecp256k1Signature-memory-arguments": 20000000000 + } + }, + "executionPrices": { + "prMem": 0.0577, + "prSteps": 0.0000721 + }, + "lovelacePerUTxOWord": 34482, + "maxBlockExUnits": { + "exUnitsMem": 50000000, + "exUnitsSteps": 40000000000 + }, + "maxCollateralInputs": 3, + "maxTxExUnits": { + "exUnitsMem": 10000000, + "exUnitsSteps": 10000000000 + }, + "maxValueSize": 5000 +} \ No newline at end of file diff --git a/integration-test/configs/local-chang/byron-genesis.json b/integration-test/configs/local-chang/byron-genesis.json new file mode 100644 index 00000000..6eaa8b49 --- /dev/null +++ b/integration-test/configs/local-chang/byron-genesis.json @@ -0,0 +1,40 @@ +{ "bootStakeholders": + { "b733bf8070781d30a0c8d5ca66392188f78c6604b631629cd055f402": 1 } +, "heavyDelegation": + { "b733bf8070781d30a0c8d5ca66392188f78c6604b631629cd055f402": + { "omega": 0 + , "issuerPk": + "ckPV1Ypq8uRkxwoDj93p7cCm4G+uB9R8SGGOKyc6KyIR8NDVVwu1FS3AwSoUjra02uiF5AlAUXUvVqZvnT8nCw==" + , "delegatePk": + "MYL9xuLMepgsQxRtqOu57nJw16pMWel79j0APRV1NSqH3ZUeBu+p7XaNoVCzw7yemMb4vwLiRDcMnnqHXztFVA==" + , "cert": + "643985a3022fedf3d9aaee8ab18d35e0cdc894beb5edb502ca47c37cce678741dd502fba0c2b8ee38513e0a75f6ee2dcc0f05d5b3c1d7ce72cc1c22a8a910909" + } } +, "startTime": 1640212228 +, "nonAvvmBalances": + { "2657WMsDfac6ef4bngGRU7FmksmW8QRfAifshdj4XyDxPeVT4DbPeoiUgzRdKjYYF": + "10020000000" } +, "blockVersionData": + { "scriptVersion": 0 + , "slotDuration": "1000" + , "maxBlockSize": "2000000" + , "maxHeaderSize": "2000000" + , "maxTxSize": "4096" + , "maxProposalSize": "700" + , "mpcThd": "20000000000000" + , "heavyDelThd": "300000000000" + , "updateVoteThd": "1000000000000" + , "updateProposalThd": "100000000000000" + , "updateImplicit": "10000" + , "softforkRule": + { "initThd": "900000000000000" + , "minThd": "600000000000000" + , "thdDecrement": "50000000000000" + } + , "txFeePolicy": + { "summand": "155381000000000" , "multiplier": "43946000000" } + , "unlockStakeEpoch": "18446744073709551615" + } +, "protocolConsts": { "k": 10 , "protocolMagic": 42 } +, "avvmDistr": {} +} \ No newline at end of file diff --git a/integration-test/configs/local-chang/byron/delegate.cert b/integration-test/configs/local-chang/byron/delegate.cert new file mode 100644 index 00000000..dcdd366a --- /dev/null +++ b/integration-test/configs/local-chang/byron/delegate.cert @@ -0,0 +1,8 @@ +{ "omega": 0 +, "issuerPk": + "ckPV1Ypq8uRkxwoDj93p7cCm4G+uB9R8SGGOKyc6KyIR8NDVVwu1FS3AwSoUjra02uiF5AlAUXUvVqZvnT8nCw==" +, "delegatePk": + "MYL9xuLMepgsQxRtqOu57nJw16pMWel79j0APRV1NSqH3ZUeBu+p7XaNoVCzw7yemMb4vwLiRDcMnnqHXztFVA==" +, "cert": + "643985a3022fedf3d9aaee8ab18d35e0cdc894beb5edb502ca47c37cce678741dd502fba0c2b8ee38513e0a75f6ee2dcc0f05d5b3c1d7ce72cc1c22a8a910909" +} \ No newline at end of file diff --git a/integration-test/configs/local-chang/byron/delegate.key b/integration-test/configs/local-chang/byron/delegate.key new file mode 100644 index 00000000..87e9c504 Binary files /dev/null and b/integration-test/configs/local-chang/byron/delegate.key differ diff --git a/integration-test/configs/local-chang/config.json b/integration-test/configs/local-chang/config.json new file mode 100644 index 00000000..d5f44b21 --- /dev/null +++ b/integration-test/configs/local-chang/config.json @@ -0,0 +1,106 @@ +{ + "ByronGenesisFile": "./byron-genesis.json", + "ShelleyGenesisFile": "./shelley-genesis.json", + "AlonzoGenesisFile": "./alonzo-genesis.json", + "ConwayGenesisFile": "./conway-genesis.json", + "SocketPath": "db/node.socket", + "Protocol": "Cardano", + "PBftSignatureThreshold": 0.6, + "RequiresNetworkMagic": "RequiresMagic", + "LastKnownBlockVersion-Alt": 0, + "LastKnownBlockVersion-Major": 3, + "LastKnownBlockVersion-Minor": 1, + "ApplicationName": "cardano-sl", + "MinNodeVersion": "9.0", + "ApplicationVersion": 1, + "TurnOnLogging": true, + "TurnOnLogMetrics": true, + "minSeverity": "Debug", + "TracingVerbosity": "NormalVerbosity", + "setupBackends": [ + "KatipBK" + ], + "defaultBackends": [ + "KatipBK" + ], + "setupScribes": [ + { + "scKind": "FileSK", + "scName": "logs/mainnet.log", + "scFormat": "ScText" + }, + { + "scKind": "StdoutSK", + "scName": "stdout", + "scFormat": "ScText" + } + ], + "defaultScribes": [ + [ + "FileSK", + "logs/mainnet.log" + ], + [ + "StdoutSK", + "stdout" + ] + ], + "rotation": { + "rpLogLimitBytes": 5000000, + "rpKeepFilesNum": 3, + "rpMaxAgeHours": 24 + }, + "TraceBlockFetchClient": false, + "TraceBlockFetchDecisions": false, + "TraceBlockFetchProtocol": false, + "TraceBlockFetchProtocolSerialised": false, + "TraceBlockFetchServer": false, + "TraceBlockchainTime": false, + "TraceChainDb": true, + "TraceChainSyncClient": false, + "TraceChainSyncBlockServer": false, + "TraceChainSyncHeaderServer": false, + "TraceChainSyncProtocol": false, + "TraceDNSResolver": true, + "TraceDNSSubscription": true, + "TraceErrorPolicy": true, + "TraceLocalErrorPolicy": true, + "TraceForge": true, + "TraceHandshake": false, + "TraceIpSubscription": true, + "TraceLocalChainSyncProtocol": false, + "TraceLocalHandshake": false, + "TraceLocalTxSubmissionProtocol": false, + "TraceLocalTxSubmissionServer": false, + "TraceMempool": true, + "TraceMux": false, + "TraceTxInbound": false, + "TraceTxOutbound": false, + "TraceTxSubmissionProtocol": false, + "options": { + "mapBackends": { + "cardano.node.metrics": [ + "EKGViewBK" + ] + }, + "mapScribes": { + "cardano.node.metrics": [ + "FileSK::logs/mainnet.log" + ] + }, + "mapSeverity": { + "cardano.node.ChainDB": "Notice", + "cardano.node.DnsSubscription": "Debug" + } + }, + "EnableLogMetrics": false, + "EnableLogging": true, + "TestShelleyHardForkAtEpoch": 0, + "TestAllegraHardForkAtEpoch": 0, + "TestMaryHardForkAtEpoch": 0, + "TestAlonzoHardForkAtEpoch": 0, + "TestBabbageHardForkAtEpoch": 10, + "TestConwayHardForkAtEpoch": 11, + "EnableDevelopmentHardForkEras": true, + "ExperimentalProtocolsEnabled": true +} \ No newline at end of file diff --git a/integration-test/configs/local-chang/conway-genesis.json b/integration-test/configs/local-chang/conway-genesis.json new file mode 100644 index 00000000..2de0f672 --- /dev/null +++ b/integration-test/configs/local-chang/conway-genesis.json @@ -0,0 +1,304 @@ +{ + "protocolParams": { + "protocolVersion": { + "minor": 0, + "major": 9 + } + }, + "poolVotingThresholds": { + "committeeNormal": 0.65, + "committeeNoConfidence": 0.65, + "hardForkInitiation": 0.51, + "motionNoConfidence": 0.6, + "ppSecurityGroup": 0.6 + }, + "dRepVotingThresholds": { + "motionNoConfidence": 0.67, + "committeeNormal": 0.67, + "committeeNoConfidence": 0.65, + "updateToConstitution": 0.75, + "hardForkInitiation": 0.6, + "ppNetworkGroup": 0.67, + "ppEconomicGroup": 0.67, + "ppTechnicalGroup": 0.67, + "ppGovGroup": 0.75, + "treasuryWithdrawal": 0.67 + }, + "committeeMinSize": 5, + "committeeMaxTermLength": 146, + "govActionLifetime": 14, + "govActionDeposit": 100000000000, + "dRepDeposit": 500000000, + "dRepActivity": 20, + "minFeeRefScriptCostPerByte": 15, + "plutusV3CostModel": [ + 100788, + 420, + 1, + 1, + 1000, + 173, + 0, + 1, + 1000, + 59957, + 4, + 1, + 11183, + 32, + 201305, + 8356, + 4, + 16000, + 100, + 16000, + 100, + 16000, + 100, + 16000, + 100, + 16000, + 100, + 16000, + 100, + 100, + 100, + 16000, + 100, + 94375, + 32, + 132994, + 32, + 61462, + 4, + 72010, + 178, + 0, + 1, + 22151, + 32, + 91189, + 769, + 4, + 2, + 85848, + 123203, + 7305, + -900, + 1716, + 549, + 57, + 85848, + 0, + 1, + 1, + 1000, + 42921, + 4, + 2, + 24548, + 29498, + 38, + 1, + 898148, + 27279, + 1, + 51775, + 558, + 1, + 39184, + 1000, + 60594, + 1, + 141895, + 32, + 83150, + 32, + 15299, + 32, + 76049, + 1, + 13169, + 4, + 22100, + 10, + 28999, + 74, + 1, + 28999, + 74, + 1, + 43285, + 552, + 1, + 44749, + 541, + 1, + 33852, + 32, + 68246, + 32, + 72362, + 32, + 7243, + 32, + 7391, + 32, + 11546, + 32, + 85848, + 123203, + 7305, + -900, + 1716, + 549, + 57, + 85848, + 0, + 1, + 90434, + 519, + 0, + 1, + 74433, + 32, + 85848, + 123203, + 7305, + -900, + 1716, + 549, + 57, + 85848, + 0, + 1, + 1, + 85848, + 123203, + 7305, + -900, + 1716, + 549, + 57, + 85848, + 0, + 1, + 955506, + 213312, + 0, + 2, + 270652, + 22588, + 4, + 1457325, + 64566, + 4, + 20467, + 1, + 4, + 0, + 141992, + 32, + 100788, + 420, + 1, + 1, + 81663, + 32, + 59498, + 32, + 20142, + 32, + 24588, + 32, + 20744, + 32, + 25933, + 32, + 24623, + 32, + 43053543, + 10, + 53384111, + 14333, + 10, + 43574283, + 26308, + 10, + 16000, + 100, + 16000, + 100, + 962335, + 18, + 2780678, + 6, + 442008, + 1, + 52538055, + 3756, + 18, + 267929, + 18, + 76433006, + 8868, + 18, + 52948122, + 18, + 1995836, + 36, + 3227919, + 12, + 901022, + 1, + 166917843, + 4307, + 36, + 284546, + 36, + 158221314, + 26549, + 36, + 74698472, + 36, + 333849714, + 1, + 254006273, + 72, + 2174038, + 72, + 2261318, + 64571, + 4, + 207616, + 8310, + 4, + 1293828, + 28716, + 63, + 0, + 1, + 1006041, + 43623, + 251, + 0, + 1 + ], + "constitution": { + "anchor": { + "url": "ipfs://QmQq5hWDNzvDR1ForEktAHrdCQmfSL2u5yctNpzDwoSBu4", + "dataHash": "23b43bebac48a4acc39e578715aa06635d6d900fa3ea7441dfffd6e43b914f7b" + }, + "script": "edcd84c10e36ae810dc50847477083069db796219b39ccde790484e0" + }, + "committee": { + "members": { + "scriptHash-7ceede7d6a89e006408e6b7c6acb3dd094b3f6817e43b4a36d01535b": 500, + "scriptHash-6095e643ea6f1cccb6e463ec34349026b3a48621aac5d512655ab1bf": 500, + "scriptHash-27999ed757d6dac217471ae61d69b1b067b8b240d9e3ff36eb66b5d0": 500, + "scriptHash-87f867a31c0f81360d4d7dcddb6b025ba8383db9bf77a2af7797799d": 500, + "scriptHash-a19a7ba1caede8f3ab3e5e2a928b3798d7d011af18fbd577f7aeb0ec": 500 + }, + "threshold": 0.67 + } +} \ No newline at end of file diff --git a/integration-test/configs/local-chang/shelley-genesis.json b/integration-test/configs/local-chang/shelley-genesis.json new file mode 100644 index 00000000..f3afd4c7 --- /dev/null +++ b/integration-test/configs/local-chang/shelley-genesis.json @@ -0,0 +1,50 @@ +{ + "maxLovelaceSupply": 1000000000000, + "securityParam": 1000000000, + "slotsPerKESPeriod": 1000000000, + "updateQuorum": 2, + "activeSlotsCoeff": 0.5, + "protocolParams": { + "minUTxOValue": 1000000, + "eMax": 18, + "extraEntropy": { + "tag": "NeutralNonce" + }, + "minFeeB": 155381, + "tau": 0.1, + "maxBlockBodySize": 65536, + "minPoolCost": 0, + "minFeeA": 44, + "maxTxSize": 16384, + "nOpt": 100, + "maxBlockHeaderSize": 1100, + "keyDeposit": 1000000, + "protocolVersion": { + "minor": 0, + "major": 9 + }, + "poolDeposit": 1000000, + "a0": 0.0, + "rho": 0.1, + "decentralisationParam": 0.1 + }, + "networkMagic": 42, + "initialFunds": { + "60d413c1745d306023e49589e658a7b7a4b4dda165ff5c97d8c8b979bf": 900000000000 + }, + "maxKESEvolutions": 60000000, + "networkId": "Testnet", + "genDelegs": { + "37c2ef3cfb83c1004fcc21c75f42fee8013ac994afde92c1af419d1c": { + "delegate": "5bd3a54bf30412243d4616c145c79467322164b81aa577814b74a520", + "vrf": "fb66920eb17f426d4f513535be0eed59859a0e83963860090bb6db571f8a5b55" + } + }, + "slotLength": 1, + "systemStart": "2021-12-21T03:17:14.803874404Z", + "staking": { + "pools": {}, + "stake": {} + }, + "epochLength": 4 +} \ No newline at end of file diff --git a/integration-test/configs/local-chang/shelley/kes.skey b/integration-test/configs/local-chang/shelley/kes.skey new file mode 100644 index 00000000..a9bfc0ca --- /dev/null +++ b/integration-test/configs/local-chang/shelley/kes.skey @@ -0,0 +1,5 @@ +{ + "type": "KesSigningKey_ed25519_kes_2^6", + "description": "KES Signing Key", + "cborHex": "59026051c2b5536d23bbd7ff92aa8b58a011fb57b669183b7083961ae979a7b2ad1fbcbf1ee580c9e39567b88562b370cdccd27cababc4812a2ce1a7a0c7369274cf5f18f3e4796482babf0ea8d4e97157d6221bb6448da0cf3f173bbc1b13e708e40c25559347cc225b6d916bf611bc133d265482d0c503e94493456bb607ce34fd7b51a13e8908d9d85582edbed89e0fd2a0fb34d45480cef5b277dbb46b23322ea191760cafdf5c2f3bc5307f2128c121e5f8f54fdf6ca2925c034fc11dcc933855b595493e629e717a1b2ced715dfac5bf42838928edd19c287d55c1ef04ecf31070fe52ab805cf813e752f001353ac637f8f3f76db4b8c0e12f8552335182af76683b819debaa623a730e12f2f7d9f63190c835e8211bdf86d2bf244e8ad114328621535a63fd1a1497389356220e818e5d2f530f50494401b7ee027172ca72093645465b2c83e0dcd1d9c4a81b6871849601a8706d95e3c58a4c0841fdfb214b0bb82ec1e18ba7bea9e4f3eb9a0abbb39e57a9ab96799379ca8cadeb2e1a8df84b3e0e7ca0af3d6665a12029f6cefe4d309c5b3fad5bec4ca7812d5bede426b6fff6f37da99a286cd837b327b35b645ca5bfabf0935ea87cbd29b3ce2b7b80f83f386a474c69f86f553e35069f40b04f9a6bb6a13b583c0a911126c8aed1301b4014e0ea8229d5dcce81a56836f5bb286bd28c1ee5c69fd358c16a4fdbd5b6e9b0ed1ef766dcf6c56c7a845104309c92a2013bd5a7c8354fb8a866b61b23e014a07a78ed5b69469f4121c97bce50864d8555b91e3c2d812f4760a6318750c7b71fccbc8bab1c54c0be28f60c97cc8e33cbd8da235e4ca9344c48f13d81a37459" +} diff --git a/integration-test/configs/local-chang/shelley/kes.vkey b/integration-test/configs/local-chang/shelley/kes.vkey new file mode 100644 index 00000000..8841f971 --- /dev/null +++ b/integration-test/configs/local-chang/shelley/kes.vkey @@ -0,0 +1,5 @@ +{ + "type": "KesVerificationKey_ed25519_kes_2^6", + "description": "KES Verification Key", + "cborHex": "58206e59b21f538b5fdbe50df62f793488f8783e19d261d3fd59a700d2c41963cec2" +} diff --git a/integration-test/configs/local-chang/shelley/node.cert b/integration-test/configs/local-chang/shelley/node.cert new file mode 100644 index 00000000..15c52608 --- /dev/null +++ b/integration-test/configs/local-chang/shelley/node.cert @@ -0,0 +1,5 @@ +{ + "type": "NodeOperationalCertificate", + "description": "", + "cborHex": "828458206e59b21f538b5fdbe50df62f793488f8783e19d261d3fd59a700d2c41963cec201005840853403f4d2e63e027b26f59c45ce81c74b1dfd708dc561b5ede5204262253451b7560f1c75425d3ee08fd4d933392f7fe3f1017efb3c8ee565a5493a061a270d582091934010118a86e2628e8188413cfa3eeac1237f3f699ebe16892f41671ccf3f" +} diff --git a/integration-test/configs/local-chang/shelley/operator.counter b/integration-test/configs/local-chang/shelley/operator.counter new file mode 100644 index 00000000..aae820c3 --- /dev/null +++ b/integration-test/configs/local-chang/shelley/operator.counter @@ -0,0 +1,5 @@ +{ + "type": "NodeOperationalCertificateIssueCounter", + "description": "Next certificate issue number: 2", + "cborHex": "8202582091934010118a86e2628e8188413cfa3eeac1237f3f699ebe16892f41671ccf3f" +} diff --git a/integration-test/configs/local-chang/shelley/operator.skey b/integration-test/configs/local-chang/shelley/operator.skey new file mode 100644 index 00000000..87464ad4 --- /dev/null +++ b/integration-test/configs/local-chang/shelley/operator.skey @@ -0,0 +1,5 @@ +{ + "type": "GenesisDelegateSigningKey_ed25519", + "description": "Genesis delegate operator key", + "cborHex": "5820351111fb3058c30c976b57f1b13e0e333243126768eae52133294cfe1481e943" +} diff --git a/integration-test/configs/local-chang/shelley/operator.vkey b/integration-test/configs/local-chang/shelley/operator.vkey new file mode 100644 index 00000000..6bd011f3 --- /dev/null +++ b/integration-test/configs/local-chang/shelley/operator.vkey @@ -0,0 +1,5 @@ +{ + "type": "GenesisDelegateVerificationKey_ed25519", + "description": "Genesis delegate operator key", + "cborHex": "582091934010118a86e2628e8188413cfa3eeac1237f3f699ebe16892f41671ccf3f" +} diff --git a/integration-test/configs/local-chang/shelley/utxo-keys/payment.addr b/integration-test/configs/local-chang/shelley/utxo-keys/payment.addr new file mode 100644 index 00000000..4d3d2e10 --- /dev/null +++ b/integration-test/configs/local-chang/shelley/utxo-keys/payment.addr @@ -0,0 +1 @@ +addr_test1vr2p8st5t5cxqglyjky7vk98k7jtfhdpvhl4e97cezuhn0cqcexl7 \ No newline at end of file diff --git a/integration-test/configs/local-chang/shelley/utxo-keys/utxo1.skey b/integration-test/configs/local-chang/shelley/utxo-keys/utxo1.skey new file mode 100644 index 00000000..896420b5 --- /dev/null +++ b/integration-test/configs/local-chang/shelley/utxo-keys/utxo1.skey @@ -0,0 +1,5 @@ +{ + "type": "GenesisUTxOSigningKey_ed25519", + "description": "Genesis Initial UTxO Signing Key", + "cborHex": "5820093be5cd3987d0c9fd8854ef908f7746b69e2d73320db6dc0f780d81585b84c2" +} diff --git a/integration-test/configs/local-chang/shelley/utxo-keys/utxo1.vkey b/integration-test/configs/local-chang/shelley/utxo-keys/utxo1.vkey new file mode 100644 index 00000000..157a8fd3 --- /dev/null +++ b/integration-test/configs/local-chang/shelley/utxo-keys/utxo1.vkey @@ -0,0 +1,5 @@ +{ + "type": "GenesisUTxOVerificationKey_ed25519", + "description": "Genesis Initial UTxO Verification Key", + "cborHex": "58208be8339e9f3addfa6810d59e2f072f85e64d4c024c087e0d24f8317c6544f62f" +} diff --git a/integration-test/configs/local-chang/shelley/vrf.skey b/integration-test/configs/local-chang/shelley/vrf.skey new file mode 100644 index 00000000..a5ff9e28 --- /dev/null +++ b/integration-test/configs/local-chang/shelley/vrf.skey @@ -0,0 +1,5 @@ +{ + "type": "VrfSigningKey_PraosVRF", + "description": "VRF Signing Key", + "cborHex": "5840b504af084d200455b08e72f0d278cf23bd9f2acddf834755d007e87536e19d1158cc502328977455f71db641249286ce07c11de5cb1f7429db0584eca3cabb7e" +} diff --git a/integration-test/configs/local-chang/shelley/vrf.vkey b/integration-test/configs/local-chang/shelley/vrf.vkey new file mode 100644 index 00000000..65c9592d --- /dev/null +++ b/integration-test/configs/local-chang/shelley/vrf.vkey @@ -0,0 +1,5 @@ +{ + "type": "VrfVerificationKey_PraosVRF", + "description": "VRF Verification Key", + "cborHex": "582058cc502328977455f71db641249286ce07c11de5cb1f7429db0584eca3cabb7e" +} diff --git a/integration-test/configs/local-chang/topology.json b/integration-test/configs/local-chang/topology.json new file mode 100644 index 00000000..dc92f2e8 --- /dev/null +++ b/integration-test/configs/local-chang/topology.json @@ -0,0 +1,9 @@ +{ + "Producers": [ + { + "addr": "172.20.0.102", + "port": 3000, + "valency": 1 + } + ] +} diff --git a/integration-test/docker-compose-chang.yml b/integration-test/docker-compose-chang.yml new file mode 100644 index 00000000..1ec314ce --- /dev/null +++ b/integration-test/docker-compose-chang.yml @@ -0,0 +1,103 @@ +version: "3.5" + +networks: + cluster: + ipam: + config: + - subnet: 172.20.0.0/24 + +services: + + cardano-node: + image: ghcr.io/intersectmbo/cardano-node:${CARDANO_NODE_VERSION:-9.1.0} + platform: linux/amd64 + entrypoint: bash + environment: + NETWORK: "${NETWORK:-local-alonzo}" + CARDANO_NODE_SOCKET_PATH: "/ipc/node.socket" + command: /code/run_node.sh + + networks: + cluster: + ipv4_address: 172.20.0.101 + + volumes: + - .:/code + - /tmp:/tmp + - node-db:/data/db + - node-ipc:/ipc + ports: + - ${BFT_NODE_PORT:-3000}:3000 + logging: + driver: "json-file" + options: + max-size: "200k" + max-file: "10" + + cardano-pool: + image: ghcr.io/intersectmbo/cardano-node:${CARDANO_NODE_VERSION:-9.1.0} + platform: linux/amd64 + entrypoint: bash + environment: + NETWORK: "${NETWORK:-local-alonzo}" + command: /code/run_pool.sh + + networks: + cluster: + ipv4_address: 172.20.0.102 + + volumes: + - .:/code + - node-ipc:/ipc + logging: + driver: "json-file" + options: + max-size: "200k" + max-file: "10" + + ogmios: + image: cardanosolutions/ogmios:v6.5.0 + platform: linux/amd64 + environment: + NETWORK: "${NETWORK:-local-alonzo}" + + command: [ + "--host", "0.0.0.0", + "--node-socket", "/ipc/node.socket", + "--node-config", "/code/configs/${NETWORK:-local-alonzo}/config.json", + "--log-level-websocket", "Debug" + ] + volumes: + - .:/code + - node-ipc:/ipc + ports: + - ${OGMIOS_PORT:-1337}:1337 + logging: + driver: "json-file" + options: + max-size: "200k" + max-file: "10" + + kupo: + image: cardanosolutions/kupo:v2.9.0 + platform: linux/amd64 + environment: + NETWORK: "${NETWORK:-local}" + + command: [ + "--node-socket", "/ipc/node.socket", + "--node-config", "/code/configs/${NETWORK:-local-alonzo}/config.json", + "--host", "0.0.0.0", + "--since", "origin", + "--match", "*", + "--in-memory" + ] + volumes: + - .:/code + - node-ipc:/ipc + ports: + - ${KUPO_PORT:-1442}:1442 + +volumes: + node-db: + node-ipc: diff --git a/integration-test/docker-compose.yml b/integration-test/docker-compose.yml index 58d45fa2..b6cd3eb0 100644 --- a/integration-test/docker-compose.yml +++ b/integration-test/docker-compose.yml @@ -10,6 +10,7 @@ services: cardano-node: image: ghcr.io/intersectmbo/cardano-node:${CARDANO_NODE_VERSION:-8.9.2} + platform: linux/amd64 entrypoint: bash environment: NETWORK: "${NETWORK:-local-alonzo}" @@ -35,6 +36,7 @@ services: cardano-pool: image: ghcr.io/intersectmbo/cardano-node:${CARDANO_NODE_VERSION:-8.9.2} + platform: linux/amd64 entrypoint: bash environment: NETWORK: "${NETWORK:-local-alonzo}" @@ -55,6 +57,7 @@ services: ogmios: image: cardanosolutions/ogmios:v6.2.0 + platform: linux/amd64 environment: NETWORK: "${NETWORK:-local-alonzo}" @@ -76,6 +79,7 @@ services: kupo: image: cardanosolutions/kupo:v2.4.0 + platform: linux/amd64 environment: NETWORK: "${NETWORK:-local}" diff --git a/integration-test/plutus_scripts/helloworldV3.plutus b/integration-test/plutus_scripts/helloworldV3.plutus new file mode 100644 index 00000000..d61b9448 --- /dev/null +++ b/integration-test/plutus_scripts/helloworldV3.plutus @@ -0,0 +1 @@ +59011d0100003232323232323225333002323232323253330073370e900118041baa0011323232533300a3370e900018059baa005132533300e0011613253333330120011616161613253330103012003132533300e3370e900018079baa005132533300f002100114a06644646600200200644a66602a00229404c94ccc04ccdc79bae301700200414a2266006006002602e0026eb0c048c04cc04cc04cc04cc04cc04cc04cc04cc040dd50059bae301230103754602460206ea801458cdc79bae3011300f375401091010d48656c6c6f2c20576f726c64210016375c002601e00260186ea801458c034c038008c030004c024dd50008b1805180580118048009804801180380098021baa00114984d9595cd2ab9d5573caae7d5d0aba25749 \ No newline at end of file diff --git a/integration-test/run_node.sh b/integration-test/run_node.sh index 1069ded0..62b72168 100755 --- a/integration-test/run_node.sh +++ b/integration-test/run_node.sh @@ -1,6 +1,6 @@ #!/bin/bash -if [ "$NETWORK" = "local-alonzo" ] || [ "$NETWORK" = "local-vasil" ] +if [ "$NETWORK" = "local-alonzo" ] || [ "$NETWORK" = "local-vasil" ] || [ "$NETWORK" = "local-chang" ] then chmod 400 /code/tmp_configs/"$NETWORK"/shelley/*.skey chmod 400 /code/tmp_configs/"$NETWORK"/shelley/*.vkey diff --git a/integration-test/run_pool.sh b/integration-test/run_pool.sh index c49bf62d..d27bfc83 100644 --- a/integration-test/run_pool.sh +++ b/integration-test/run_pool.sh @@ -1,7 +1,7 @@ #!/bin/bash echo "$NETWORK" -if [ "$NETWORK" = "local-alonzo" ] || [ "$NETWORK" = "local-vasil" ] +if [ "$NETWORK" = "local-alonzo" ] || [ "$NETWORK" = "local-vasil" ] || [ "$NETWORK" = "local-chang" ] then # Waiting for BFT node to be ready @@ -15,7 +15,7 @@ done cardano-cli transaction build \ --tx-in 732bfd67e66be8e8288349fcaaa2294973ef6271cc189a239bb431275401b8e5#0 \ --tx-out "$(cat /code/keys/pool/full.addr)"+450000000000 \ - --change-address "$(cat /code/tmp_configs/local-alonzo/shelley/utxo-keys/payment.addr)" \ + --change-address "$(cat /code/tmp_configs/"$NETWORK"/shelley/utxo-keys/payment.addr)" \ --out-file tx.raw \ --testnet-magic 42 \ --certificate-file /code/keys/pool/stake.cert \ @@ -29,7 +29,7 @@ done cardano-cli transaction sign \ --tx-body-file tx.raw \ - --signing-key-file /code/tmp_configs/local-alonzo/shelley/utxo-keys/utxo1.skey \ + --signing-key-file /code/tmp_configs/"$NETWORK"/shelley/utxo-keys/utxo1.skey \ --signing-key-file /code/keys/pool/stake.skey \ --signing-key-file /code/keys/pool/cold.skey \ --testnet-magic 42 \ diff --git a/integration-test/run_tests.sh b/integration-test/run_tests.sh index 45670042..906eb979 100755 --- a/integration-test/run_tests.sh +++ b/integration-test/run_tests.sh @@ -6,52 +6,78 @@ set -o pipefail ROOT=$(pwd) poetry install -poetry run pip install ogmios +#poetry run pip install ogmios ########## # Alonzo # ########## +# +## Cleanup containers and volumes in case there is any running +#docker-compose down --volumes --remove-orphans +# +## Run alonzo integration tests +#./bootstrap.sh local-alonzo +# +## Launch containers +#docker-compose up -d +# +#export PAYMENT_KEY="$ROOT"/configs/local-alonzo/shelley/utxo-keys/utxo1.skey +#export EXTENDED_PAYMENT_KEY="$ROOT"/keys/extended.skey +#export POOL_ID=$(cat "$ROOT"/keys/pool/pool.id) +# +## Wait for stake pool to start producing blocks +#sleep 10 +# +## Cleanup +#docker-compose down --volumes --remove-orphans +# +########## +## Vasil # +########## +# +## Cleanup containers and volumes in case there is any running +#docker-compose down --volumes --remove-orphans +# +## Run integration tests +#./bootstrap.sh local-vasil +# +## Launch containers +#docker-compose up -d +# +#export PAYMENT_KEY="$ROOT"/configs/local-vasil/shelley/utxo-keys/utxo1.skey +#export EXTENDED_PAYMENT_KEY="$ROOT"/keys/extended.skey +#export POOL_ID=$(cat "$ROOT"/keys/pool/pool.id) +# +## Wait for stake pool to start producing blocks +#sleep 30 +# +#poetry run pytest -s -vv -n 4 "$ROOT"/test +# +## Cleanup +#docker-compose down --volumes --remove-orphans -# Cleanup containers and volumes in case there is any running -docker-compose down --volumes --remove-orphans - -# Run alonzo integration tests -./bootstrap.sh local-alonzo - -# Launch containers -docker-compose up -d - -export PAYMENT_KEY="$ROOT"/configs/local-alonzo/shelley/utxo-keys/utxo1.skey -export EXTENDED_PAYMENT_KEY="$ROOT"/keys/extended.skey -export POOL_ID=$(cat "$ROOT"/keys/pool/pool.id) - -# Wait for stake pool to start producing blocks -sleep 10 - -# Cleanup -docker-compose down --volumes --remove-orphans ######### -# Vasil # +# Chang # ######### # Cleanup containers and volumes in case there is any running -docker-compose down --volumes --remove-orphans +docker compose -f docker-compose-chang.yml down --volumes --remove-orphans # Run integration tests -./bootstrap.sh local-vasil +./bootstrap.sh local-chang # Launch containers -docker-compose up -d +docker compose -f docker-compose-chang.yml up -d -export PAYMENT_KEY="$ROOT"/configs/local-vasil/shelley/utxo-keys/utxo1.skey +export PAYMENT_KEY="$ROOT"/configs/local-chang/shelley/utxo-keys/utxo1.skey export EXTENDED_PAYMENT_KEY="$ROOT"/keys/extended.skey export POOL_ID=$(cat "$ROOT"/keys/pool/pool.id) # Wait for stake pool to start producing blocks sleep 30 -poetry run pytest -s -vv "$ROOT"/test +poetry run pytest -m "not (CardanoCLI)" -s -vv -n 4 "$ROOT"/test --cov=pycardano --cov-config=../.coveragerc --cov-report=xml:../coverage.xml # Cleanup -docker-compose down --volumes --remove-orphans \ No newline at end of file +docker compose -f docker-compose-chang.yml down --volumes --remove-orphans \ No newline at end of file diff --git a/integration-test/test/base.py b/integration-test/test/base.py index 2491c4b2..2c0e8f67 100644 --- a/integration-test/test/base.py +++ b/integration-test/test/base.py @@ -7,7 +7,7 @@ from pycardano import * -TEST_RETRIES = 6 +TEST_RETRIES = 8 @retry(tries=10, delay=4) @@ -22,8 +22,11 @@ class TestBase: # TODO: Bring back kupo test KUPO_URL = "http://localhost:1442" - chain_context = python_ogmios.OgmiosChainContext( - host="localhost", port=1337, network=Network.TESTNET + chain_context = OgmiosV6ChainContext( + host="localhost", + port=1337, + network=Network.TESTNET, + refetch_chain_tip_interval=1, ) check_chain_context(chain_context) diff --git a/integration-test/test/test_cardano_cli.py b/integration-test/test/test_cardano_cli.py index 8a1d875c..1b484a8d 100644 --- a/integration-test/test/test_cardano_cli.py +++ b/integration-test/test/test_cardano_cli.py @@ -1,6 +1,7 @@ import os from pathlib import Path +import pytest from retry import retry from pycardano import ( @@ -15,6 +16,7 @@ from .base import TEST_RETRIES +@pytest.mark.CardanoCLI class TestCardanoCli: network_env = os.getenv("NETWORK", "local-alonzo") host_socket = os.getenv("DOCKER_HOST", None) diff --git a/integration-test/test/test_plutus.py b/integration-test/test/test_plutus.py index 93acf491..965bc0f9 100644 --- a/integration-test/test/test_plutus.py +++ b/integration-test/test/test_plutus.py @@ -1,5 +1,6 @@ import collections import time +from dataclasses import dataclass from typing import Dict, Union import cbor2 @@ -7,11 +8,24 @@ from retry import retry from pycardano import * +from pycardano.backend.kupo import KupoChainContextExtension from .base import TEST_RETRIES, TestBase from .test_cardano_cli import TestCardanoCli +@dataclass +class HelloWorldDatum(PlutusData): + CONSTR_ID = 0 + owner: bytes + + +@dataclass +class HelloWorldRedeemer(PlutusData): + CONSTR_ID = 0 + msg: bytes + + class TestPlutus(TestBase): @retry(tries=TEST_RETRIES, backoff=1.5, delay=6, jitter=(0, 4)) def test_plutus_v1(self): @@ -263,7 +277,7 @@ def test_plutus_v2_ref_script(self): print(signed_tx.to_cbor_hex()) print("############### Submitting transaction ###############") self.chain_context.submit_tx(signed_tx) - time.sleep(3) + time.sleep(6) # ----------- Send ADA to the same script address without datum or script --------------- @@ -280,7 +294,7 @@ def test_plutus_v2_ref_script(self): print(signed_tx.to_cbor_hex()) print("############### Submitting transaction ###############") self.chain_context.submit_tx(signed_tx) - time.sleep(3) + time.sleep(6) # ----------- Taker take --------------- @@ -369,11 +383,72 @@ def test_get_plutus_script(self): assert utxos[0].output.script == forty_two_script + @retry(tries=TEST_RETRIES, backoff=1.5, delay=6, jitter=(0, 4)) + @pytest.mark.post_chang + def test_plutus_v3(self): + # ----------- Giver give --------------- + + with open("./plutus_scripts/helloworldV3.plutus", "r") as f: + script_hex = f.read() + hello_world_script = bytes.fromhex(script_hex) + + script_hash = plutus_script_hash(PlutusV3Script(hello_world_script)) + + print("script_hash: ", script_hash) + + script_address = Address(script_hash, network=self.NETWORK) + + giver_address = Address(self.payment_vkey.hash(), network=self.NETWORK) + + builder = TransactionBuilder(self.chain_context) + builder.add_input_address(giver_address) + datum = HelloWorldDatum(owner=self.payment_vkey.hash().to_primitive()) + builder.add_output(TransactionOutput(script_address, 50000000, datum=datum)) + + signed_tx = builder.build_and_sign([self.payment_skey], giver_address) + + print("############### Transaction created ###############") + print(signed_tx) + print(signed_tx.to_cbor_hex()) + print("############### Submitting transaction ###############") + self.chain_context.submit_tx(signed_tx) + time.sleep(3) + + # ----------- Taker take --------------- + + redeemer = Redeemer(data=HelloWorldRedeemer(msg=b"Hello, World!")) + + utxo_to_spend = self.chain_context.utxos(script_address)[0] + + taker_address = Address(self.payment_vkey.hash(), network=self.NETWORK) + + builder = TransactionBuilder(self.chain_context) + + builder.add_script_input( + utxo_to_spend, PlutusV3Script(hello_world_script), redeemer=redeemer + ) + take_output = TransactionOutput(taker_address, 25123456) + builder.add_output(take_output) + + builder.required_signers = [self.payment_vkey.hash()] -# class TestPlutusOgmiosOnly(TestPlutus): -# @classmethod -# def setup_class(cls): -# cls.chain_context._kupo_url = None + signed_tx = builder.build_and_sign([self.payment_skey], taker_address) + + print("############### Transaction created ###############") + print(signed_tx) + print(signed_tx.to_cbor_hex()) + print("############### Submitting transaction ###############") + self.chain_context.submit_tx(signed_tx) + + time.sleep(3) + + self.assert_output(taker_address, take_output) + + +class TestPlutusKupoOgmios(TestPlutus): + @classmethod + def setup_class(cls): + cls.chain_context = KupoChainContextExtension(cls.chain_context, cls.KUPO_URL) def evaluate_tx(tx: Transaction) -> Dict[str, ExecutionUnits]: @@ -388,6 +463,7 @@ def evaluate_tx(tx: Transaction) -> Dict[str, ExecutionUnits]: return execution_units +@pytest.mark.CardanoCLI class TestPlutusCardanoCLI(TestPlutus): @classmethod def setup_class(cls): diff --git a/integration-test/test/test_zero_empty_asset.py b/integration-test/test/test_zero_empty_asset.py new file mode 100644 index 00000000..71ca83c0 --- /dev/null +++ b/integration-test/test/test_zero_empty_asset.py @@ -0,0 +1,205 @@ +import pathlib +import tempfile + +import pytest +from retry import retry + +from pycardano import * + +from .base import TEST_RETRIES, TestBase + + +class TestZeroEmptyAsset(TestBase): + @retry(tries=TEST_RETRIES, backoff=1.5, delay=6, jitter=(0, 4)) + @pytest.mark.post_chang + def test_submit_zero_and_empty(self): + address = Address(self.payment_vkey.hash(), network=self.NETWORK) + + # Load payment keys or create them if they don't exist + def load_or_create_key_pair(base_dir, base_name): + skey_path = base_dir / f"{base_name}.skey" + vkey_path = base_dir / f"{base_name}.vkey" + + if skey_path.exists(): + skey = PaymentSigningKey.load(str(skey_path)) + vkey = PaymentVerificationKey.from_signing_key(skey) + else: + key_pair = PaymentKeyPair.generate() + key_pair.signing_key.save(str(skey_path)) + key_pair.verification_key.save(str(vkey_path)) + skey = key_pair.signing_key + vkey = key_pair.verification_key + return skey, vkey + + tempdir = tempfile.TemporaryDirectory() + PROJECT_ROOT = tempdir.name + + root = pathlib.Path(PROJECT_ROOT) + # Create the directory if it doesn't exist + root.mkdir(parents=True, exist_ok=True) + """Generate keys""" + key_dir = root / "keys" + key_dir.mkdir(exist_ok=True) + + # Generate policy keys, which will be used when minting NFT + policy_skey, policy_vkey = load_or_create_key_pair(key_dir, "policy") + + """Create policy""" + # A policy that requires a signature from the policy key we generated above + pub_key_policy_1 = ScriptPubkey(policy_vkey.hash()) + + # A policy that requires a signature from the extended payment key + pub_key_policy_2 = ScriptPubkey(self.extended_payment_vkey.hash()) + + # Combine two policies using ScriptAll policy + policy = ScriptAll([pub_key_policy_1, pub_key_policy_2]) + + # Calculate policy ID, which is the hash of the policy + policy_id = policy.hash() + + """Define NFT""" + my_nft = MultiAsset.from_primitive( + { + policy_id.payload: { + b"MY_NFT_1": 1, # Name of our NFT1 # Quantity of this NFT + b"MY_NFT_2": 1, # Name of our NFT2 # Quantity of this NFT + } + } + ) + + native_scripts = [policy] + + """Create metadata""" + # We need to create a metadata for our NFTs, so they could be displayed correctly by blockchain explorer + metadata = { + 721: { # 721 refers to the metadata label registered for NFT standard here: + # https://github.com/cardano-foundation/CIPs/blob/master/CIP-0010/registry.json#L14-L17 + policy_id.payload.hex(): { + "MY_NFT_1": { + "description": "This is my first NFT thanks to PyCardano", + "name": "PyCardano NFT example token 1", + "id": 1, + "image": "ipfs://QmRhTTbUrPYEw3mJGGhQqQST9k86v1DPBiTTWJGKDJsVFw", + }, + "MY_NFT_2": { + "description": "This is my second NFT thanks to PyCardano", + "name": "PyCardano NFT example token 2", + "id": 2, + "image": "ipfs://QmRhTTbUrPYEw3mJGGhQqQST9k86v1DPBiTTWJGKDJsVFw", + }, + } + } + } + + # Place metadata in AuxiliaryData, the format acceptable by a transaction. + auxiliary_data = AuxiliaryData(AlonzoMetadata(metadata=Metadata(metadata))) + + """Build mint transaction""" + + # Create a transaction builder + builder = TransactionBuilder(self.chain_context) + + # Add our own address as the input address + builder.add_input_address(address) + + # Set nft we want to mint + builder.mint = my_nft + + # Set native script + builder.native_scripts = native_scripts + + # Set transaction metadata + builder.auxiliary_data = auxiliary_data + + # Calculate the minimum amount of lovelace that need to hold the NFT we are going to mint + min_val = min_lovelace_pre_alonzo(Value(0, my_nft), self.chain_context) + + # Send the NFT to our own address + nft_output = TransactionOutput(address, Value(min_val, my_nft)) + builder.add_output(nft_output) + + # Build and sign transaction + signed_tx = builder.build_and_sign( + [self.payment_skey, self.extended_payment_skey, policy_skey], address + ) + + print("############### Transaction created ###############") + print(signed_tx) + print(signed_tx.to_cbor_hex()) + + # Submit signed transaction to the network + print("############### Submitting transaction ###############") + self.chain_context.submit_tx(signed_tx) + + self.assert_output(address, nft_output) + + """Build transaction with 0 nft""" + + # Create a transaction builder + builder = TransactionBuilder(self.chain_context) + + # Add our own address as the input address + builder.add_input_address(address) + + # Calculate the minimum amount of lovelace that need to hold the NFT we are going to mint + min_val = min_lovelace_pre_alonzo(Value(0), self.chain_context) + + # Send the NFT to our own address + nft_output = TransactionOutput( + address, + Value( + min_val, + MultiAsset.from_primitive( + {policy_vkey.hash().payload: {b"MY_NFT_1": 0}} + ), + ), + ) + builder.add_output(nft_output) + + # Build and sign transaction + signed_tx = builder.build_and_sign( + [self.payment_skey, self.extended_payment_skey], address + ) + + print("############### Transaction created ###############") + print(signed_tx) + print(signed_tx.to_cbor_hex()) + + # Submit signed transaction to the network + print("############### Submitting transaction ###############") + self.chain_context.submit_tx(signed_tx) + + self.assert_output(address, nft_output) + + """Build transaction with empty multi-asset""" + + # Create a transaction builder + builder = TransactionBuilder(self.chain_context) + + # Add our own address as the input address + builder.add_input_address(address) + + # Calculate the minimum amount of lovelace that need to hold the NFT we are going to mint + min_val = min_lovelace_pre_alonzo(Value(0), self.chain_context) + + # Send the NFT to our own address + nft_output = TransactionOutput( + address, + Value(min_val, MultiAsset.from_primitive({policy_vkey.hash().payload: {}})), + ) + builder.add_output(nft_output) + + # Build and sign transaction + signed_tx = builder.build_and_sign( + [self.payment_skey, self.extended_payment_skey], address + ) + + print("############### Transaction created ###############") + print(signed_tx) + print(signed_tx.to_cbor_hex()) + + # Submit signed transaction to the network + print("############### Submitting transaction ###############") + self.chain_context.submit_tx(signed_tx) + + self.assert_output(address, nft_output) diff --git a/poetry.lock b/poetry.lock index 7d8d4ff3..29717e91 100644 --- a/poetry.lock +++ b/poetry.lock @@ -11,6 +11,20 @@ files = [ {file = "alabaster-0.7.13.tar.gz", hash = "sha256:a27a4a084d5e690e16e01e03ad2b2e552c61a65469419b907243193de1a84ae2"}, ] +[[package]] +name = "annotated-types" +version = "0.7.0" +description = "Reusable constraint types to use with typing.Annotated" +optional = false +python-versions = ">=3.8" +files = [ + {file = "annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53"}, + {file = "annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89"}, +] + +[package.dependencies] +typing-extensions = {version = ">=4.0.0", markers = "python_version < \"3.9\""} + [[package]] name = "asn1crypto" version = "1.5.1" @@ -24,32 +38,32 @@ files = [ [[package]] name = "attrs" -version = "23.2.0" +version = "24.2.0" description = "Classes Without Boilerplate" optional = false python-versions = ">=3.7" files = [ - {file = "attrs-23.2.0-py3-none-any.whl", hash = "sha256:99b87a485a5820b23b879f04c2305b44b951b502fd64be915879d77a7e8fc6f1"}, - {file = "attrs-23.2.0.tar.gz", hash = "sha256:935dc3b529c262f6cf76e50877d35a4bd3c1de194fd41f47a2b7ae8f19971f30"}, + {file = "attrs-24.2.0-py3-none-any.whl", hash = "sha256:81921eb96de3191c8258c199618104dd27ac608d9366f5e35d011eae1867ede2"}, + {file = "attrs-24.2.0.tar.gz", hash = "sha256:5cfb1b9148b5b086569baec03f20d7b6bf3bcacc9a42bebf87ffaaca362f6346"}, ] [package.extras] -cov = ["attrs[tests]", "coverage[toml] (>=5.3)"] -dev = ["attrs[tests]", "pre-commit"] -docs = ["furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier", "zope-interface"] -tests = ["attrs[tests-no-zope]", "zope-interface"] -tests-mypy = ["mypy (>=1.6)", "pytest-mypy-plugins"] -tests-no-zope = ["attrs[tests-mypy]", "cloudpickle", "hypothesis", "pympler", "pytest (>=4.3.0)", "pytest-xdist[psutil]"] +benchmark = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-codspeed", "pytest-mypy-plugins", "pytest-xdist[psutil]"] +cov = ["cloudpickle", "coverage[toml] (>=5.3)", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] +dev = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pre-commit", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] +docs = ["cogapp", "furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier (<24.7)"] +tests = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] +tests-mypy = ["mypy (>=1.11.1)", "pytest-mypy-plugins"] [[package]] name = "babel" -version = "2.15.0" +version = "2.16.0" description = "Internationalization utilities" optional = false python-versions = ">=3.8" files = [ - {file = "Babel-2.15.0-py3-none-any.whl", hash = "sha256:08706bdad8d0a3413266ab61bd6c34d0c28d6e1e7badf40a2cebe67644e2e1fb"}, - {file = "babel-2.15.0.tar.gz", hash = "sha256:8daf0e265d05768bc6c7a314cf1321e9a123afc328cc635c18622a2f30a04413"}, + {file = "babel-2.16.0-py3-none-any.whl", hash = "sha256:368b5b98b37c06b7daf6696391c3240c938b37767d4584413e8438c5c435fa8b"}, + {file = "babel-2.16.0.tar.gz", hash = "sha256:d1f3554ca26605fe173f3de0c65f750f5a42f924499bf134de6423582298e316"}, ] [package.dependencies] @@ -60,33 +74,33 @@ dev = ["freezegun (>=1.0,<2.0)", "pytest (>=6.0)", "pytest-cov"] [[package]] name = "black" -version = "24.4.2" +version = "24.8.0" description = "The uncompromising code formatter." optional = false python-versions = ">=3.8" files = [ - {file = "black-24.4.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:dd1b5a14e417189db4c7b64a6540f31730713d173f0b63e55fabd52d61d8fdce"}, - {file = "black-24.4.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8e537d281831ad0e71007dcdcbe50a71470b978c453fa41ce77186bbe0ed6021"}, - {file = "black-24.4.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eaea3008c281f1038edb473c1aa8ed8143a5535ff18f978a318f10302b254063"}, - {file = "black-24.4.2-cp310-cp310-win_amd64.whl", hash = "sha256:7768a0dbf16a39aa5e9a3ded568bb545c8c2727396d063bbaf847df05b08cd96"}, - {file = "black-24.4.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:257d724c2c9b1660f353b36c802ccece186a30accc7742c176d29c146df6e474"}, - {file = "black-24.4.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:bdde6f877a18f24844e381d45e9947a49e97933573ac9d4345399be37621e26c"}, - {file = "black-24.4.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e151054aa00bad1f4e1f04919542885f89f5f7d086b8a59e5000e6c616896ffb"}, - {file = "black-24.4.2-cp311-cp311-win_amd64.whl", hash = "sha256:7e122b1c4fb252fd85df3ca93578732b4749d9be076593076ef4d07a0233c3e1"}, - {file = "black-24.4.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:accf49e151c8ed2c0cdc528691838afd217c50412534e876a19270fea1e28e2d"}, - {file = "black-24.4.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:88c57dc656038f1ab9f92b3eb5335ee9b021412feaa46330d5eba4e51fe49b04"}, - {file = "black-24.4.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:be8bef99eb46d5021bf053114442914baeb3649a89dc5f3a555c88737e5e98fc"}, - {file = "black-24.4.2-cp312-cp312-win_amd64.whl", hash = "sha256:415e686e87dbbe6f4cd5ef0fbf764af7b89f9057b97c908742b6008cc554b9c0"}, - {file = "black-24.4.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:bf10f7310db693bb62692609b397e8d67257c55f949abde4c67f9cc574492cc7"}, - {file = "black-24.4.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:98e123f1d5cfd42f886624d84464f7756f60ff6eab89ae845210631714f6db94"}, - {file = "black-24.4.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:48a85f2cb5e6799a9ef05347b476cce6c182d6c71ee36925a6c194d074336ef8"}, - {file = "black-24.4.2-cp38-cp38-win_amd64.whl", hash = "sha256:b1530ae42e9d6d5b670a34db49a94115a64596bc77710b1d05e9801e62ca0a7c"}, - {file = "black-24.4.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:37aae07b029fa0174d39daf02748b379399b909652a806e5708199bd93899da1"}, - {file = "black-24.4.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:da33a1a5e49c4122ccdfd56cd021ff1ebc4a1ec4e2d01594fef9b6f267a9e741"}, - {file = "black-24.4.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ef703f83fc32e131e9bcc0a5094cfe85599e7109f896fe8bc96cc402f3eb4b6e"}, - {file = "black-24.4.2-cp39-cp39-win_amd64.whl", hash = "sha256:b9176b9832e84308818a99a561e90aa479e73c523b3f77afd07913380ae2eab7"}, - {file = "black-24.4.2-py3-none-any.whl", hash = "sha256:d36ed1124bb81b32f8614555b34cc4259c3fbc7eec17870e8ff8ded335b58d8c"}, - {file = "black-24.4.2.tar.gz", hash = "sha256:c872b53057f000085da66a19c55d68f6f8ddcac2642392ad3a355878406fbd4d"}, + {file = "black-24.8.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:09cdeb74d494ec023ded657f7092ba518e8cf78fa8386155e4a03fdcc44679e6"}, + {file = "black-24.8.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:81c6742da39f33b08e791da38410f32e27d632260e599df7245cccee2064afeb"}, + {file = "black-24.8.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:707a1ca89221bc8a1a64fb5e15ef39cd755633daa672a9db7498d1c19de66a42"}, + {file = "black-24.8.0-cp310-cp310-win_amd64.whl", hash = "sha256:d6417535d99c37cee4091a2f24eb2b6d5ec42b144d50f1f2e436d9fe1916fe1a"}, + {file = "black-24.8.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:fb6e2c0b86bbd43dee042e48059c9ad7830abd5c94b0bc518c0eeec57c3eddc1"}, + {file = "black-24.8.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:837fd281f1908d0076844bc2b801ad2d369c78c45cf800cad7b61686051041af"}, + {file = "black-24.8.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:62e8730977f0b77998029da7971fa896ceefa2c4c4933fcd593fa599ecbf97a4"}, + {file = "black-24.8.0-cp311-cp311-win_amd64.whl", hash = "sha256:72901b4913cbac8972ad911dc4098d5753704d1f3c56e44ae8dce99eecb0e3af"}, + {file = "black-24.8.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:7c046c1d1eeb7aea9335da62472481d3bbf3fd986e093cffd35f4385c94ae368"}, + {file = "black-24.8.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:649f6d84ccbae73ab767e206772cc2d7a393a001070a4c814a546afd0d423aed"}, + {file = "black-24.8.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2b59b250fdba5f9a9cd9d0ece6e6d993d91ce877d121d161e4698af3eb9c1018"}, + {file = "black-24.8.0-cp312-cp312-win_amd64.whl", hash = "sha256:6e55d30d44bed36593c3163b9bc63bf58b3b30e4611e4d88a0c3c239930ed5b2"}, + {file = "black-24.8.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:505289f17ceda596658ae81b61ebbe2d9b25aa78067035184ed0a9d855d18afd"}, + {file = "black-24.8.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:b19c9ad992c7883ad84c9b22aaa73562a16b819c1d8db7a1a1a49fb7ec13c7d2"}, + {file = "black-24.8.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1f13f7f386f86f8121d76599114bb8c17b69d962137fc70efe56137727c7047e"}, + {file = "black-24.8.0-cp38-cp38-win_amd64.whl", hash = "sha256:f490dbd59680d809ca31efdae20e634f3fae27fba3ce0ba3208333b713bc3920"}, + {file = "black-24.8.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:eab4dd44ce80dea27dc69db40dab62d4ca96112f87996bca68cd75639aeb2e4c"}, + {file = "black-24.8.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:3c4285573d4897a7610054af5a890bde7c65cb466040c5f0c8b732812d7f0e5e"}, + {file = "black-24.8.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9e84e33b37be070ba135176c123ae52a51f82306def9f7d063ee302ecab2cf47"}, + {file = "black-24.8.0-cp39-cp39-win_amd64.whl", hash = "sha256:73bbf84ed136e45d451a260c6b73ed674652f90a2b3211d6a35e78054563a9bb"}, + {file = "black-24.8.0-py3-none-any.whl", hash = "sha256:972085c618ee94f402da1af548a4f218c754ea7e5dc70acb168bfaca4c2542ed"}, + {file = "black-24.8.0.tar.gz", hash = "sha256:2500945420b6784c38b9ee885af039f5e7471ef284ab03fa35ecdde4688cd83f"}, ] [package.dependencies] @@ -117,13 +131,13 @@ files = [ [[package]] name = "blockfrost-python" -version = "0.5.3" +version = "0.6.0" description = "The official Python SDK for Blockfrost API v0.1.37" optional = false -python-versions = ">=3.7, <4" +python-versions = "<4,>=3.7" files = [ - {file = "blockfrost-python-0.5.3.tar.gz", hash = "sha256:3154b99867e7714c90064c9e1a37e3b7af97c107b64549dd0d424aaa3209017e"}, - {file = "blockfrost_python-0.5.3-py3-none-any.whl", hash = "sha256:b0e73f09f1ff06977c85ccd63f6afe7ec30fa1b5c48e94a15d8bc8cf1f61997b"}, + {file = "blockfrost_python-0.6.0-py3-none-any.whl", hash = "sha256:c88840b8034b30dc06c637ccd14806e472d830d63522d2a667d9263640a354f4"}, + {file = "blockfrost_python-0.6.0.tar.gz", hash = "sha256:764b795617aadfd712b2a214fa6bd26cca33f0008340e0225126d18be040b112"}, ] [package.dependencies] @@ -131,59 +145,74 @@ requests = "*" [[package]] name = "cachetools" -version = "5.3.3" +version = "5.5.0" description = "Extensible memoizing collections and decorators" optional = false python-versions = ">=3.7" files = [ - {file = "cachetools-5.3.3-py3-none-any.whl", hash = "sha256:0abad1021d3f8325b2fc1d2e9c8b9c9d57b04c3932657a72465447332c24d945"}, - {file = "cachetools-5.3.3.tar.gz", hash = "sha256:ba29e2dfa0b8b556606f097407ed1aa62080ee108ab0dc5ec9d6a723a007d105"}, + {file = "cachetools-5.5.0-py3-none-any.whl", hash = "sha256:02134e8439cdc2ffb62023ce1debca2944c3f289d66bb17ead3ab3dede74b292"}, + {file = "cachetools-5.5.0.tar.gz", hash = "sha256:2cc24fb4cbe39633fb7badd9db9ca6295d766d9c2995f245725a46715d050f2a"}, +] + +[[package]] +name = "cardano-tools" +version = "2.1.0" +description = "A collection of tools to enable development in the Cardano ecosystem using the Python programming language." +optional = false +python-versions = ">=3.8,<4.0" +files = [ + {file = "cardano_tools-2.1.0-py3-none-any.whl", hash = "sha256:c562c234b3d9a51540d41432f88aeae9a68c9441e0ea363c675dd712380ca06c"}, + {file = "cardano_tools-2.1.0.tar.gz", hash = "sha256:445c8a5c769f57e5e04494ac4e3012082c3d0f1bd9a9eaed7f834d37ad7a069e"}, ] +[package.dependencies] +pexpect = ">=4.8.0,<5.0.0" +requests = ">=2.28.0,<3.0.0" + [[package]] name = "cbor2" -version = "5.6.3" +version = "5.6.4" description = "CBOR (de)serializer with extensive tag support" optional = false python-versions = ">=3.8" files = [ - {file = "cbor2-5.6.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0201d5e8d9ad1557aeb50d35b907c0f170de0ae9ebb484b2894bcee3b2e13b80"}, - {file = "cbor2-5.6.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:eda6965cca276d4c2cebdbee14572dec65b991c5359fc32a793f03f052e35985"}, - {file = "cbor2-5.6.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:14561038b8eaab3fd5e867f09bc43f7525a1405e41ade14066925ea3d42513a8"}, - {file = "cbor2-5.6.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9a3cf6b339a005031e4b8c79b9541856e3b0077ea4c33d7bb6a019885136f53a"}, - {file = "cbor2-5.6.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:4b7636d39de203ee30ac13575ed3e9a0510e993fa1671022b84b9e35e369825f"}, - {file = "cbor2-5.6.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:23847075ce1bcda871c7698e5db0635685995ae470098a5e4c9a26c00f65f21a"}, - {file = "cbor2-5.6.3-cp310-cp310-win_amd64.whl", hash = "sha256:ca15be7142e861fb9f918e0248620b4d4153b9ff14ef6034f7204db5db2924a1"}, - {file = "cbor2-5.6.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b07ee755ae5b0dfad608dab37364b35895cab5d1222653da1fea32a10330c4b0"}, - {file = "cbor2-5.6.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:9fc063843c14e9e95181faf8d807a53c958d77bb9d360eb4f2344d075ecfed36"}, - {file = "cbor2-5.6.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c66d4c227c2ed6c63ec5c2d50eb8ec0e1c41c07b452a867544e48ca41d4f0b64"}, - {file = "cbor2-5.6.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3af60ac82a733bfdfb2b1079c850fefea2621bdb8c8f87f4c5d12802d48a8c55"}, - {file = "cbor2-5.6.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:acb93292843aa72768f089a135bfeec4c9b745132e8dc22f1b149490fc77cb0a"}, - {file = "cbor2-5.6.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:193d1abdffd52893710d39389daa5c03e1569421cdf53585a28033689aef7aec"}, - {file = "cbor2-5.6.3-cp311-cp311-win_amd64.whl", hash = "sha256:d0c915db92b441f505f8a14a521c9461439ac8e5d959454845eb92f93db0bb3b"}, - {file = "cbor2-5.6.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:9eaec8c04618124a6b597fe4471035cb7cb0d5114f43aaf2062821ad480ef57c"}, - {file = "cbor2-5.6.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:d1e5181d4f858237ab4e1a28e21bdcaf31dab2657ab60a8d4a0701a078fe5926"}, - {file = "cbor2-5.6.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:277997127402710a3abdf4372ac75e8f8bb2e75a303cd789312e515c8ef657dd"}, - {file = "cbor2-5.6.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:add01e4b4663199940d10f8c8e1d926e70823d1b2f3f981cc097a4764125f110"}, - {file = "cbor2-5.6.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:adc87485ffd7a4dad481e08e6819eebfcfbafc0918fffcca47aee4cdf8c6de04"}, - {file = "cbor2-5.6.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:ea4a0412426155c3b78763449db56cf5c72c48788a37d7e60bd66c844b9c8634"}, - {file = "cbor2-5.6.3-cp312-cp312-win_amd64.whl", hash = "sha256:18b3dee4eddde9761c60298ce21c0cd4e770237978034c5ee1d4242e255683ec"}, - {file = "cbor2-5.6.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:ff6fd1c54b97ee322c0b7180092305ca3b012ff78fddadad97b33490f5f8881f"}, - {file = "cbor2-5.6.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:ac6f10b9d25f2d61c036f86238bf23e3ea0253f98faa8ab00f67228bf3c0ce2a"}, - {file = "cbor2-5.6.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7be74f2cbda547fdd57c83ee5b3470804f02c660db28efcf9d4016f001b66f40"}, - {file = "cbor2-5.6.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:64ea120206f82492a4385bbc5e2639f9b67c8bc7bdc57bffcbe9a8fee8cd6342"}, - {file = "cbor2-5.6.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:c3d2902e1aed155d56cdcae99cd4a9dae843e3fff6978148d2d5d5f9a0b986cd"}, - {file = "cbor2-5.6.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:2d4f95a567e26d8d9d62db234cd089525c52f19e7fdd59152629d9f03bd94b4f"}, - {file = "cbor2-5.6.3-cp38-cp38-win_amd64.whl", hash = "sha256:33efbe7103bac090430d291fca2fe1c444b0ec55c4716e8051b72a81377e8b79"}, - {file = "cbor2-5.6.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:81e619a2a59ae966cedb5fd3ea8a9487a3d4430824bbeacdcf5f74ad6112cc57"}, - {file = "cbor2-5.6.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:2b7755b93d32638f4d79a0fa0744b423787f6faa3c96ccccac68b6dbf1848368"}, - {file = "cbor2-5.6.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0f0e95011ae8460265ef348fe380664fa22c51015fd52344ebd781579fa9552a"}, - {file = "cbor2-5.6.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7693e53c3ba0b2ad4e46b610f8d69159ffdbcb6ebe75ea1c1f5f40c3283639ca"}, - {file = "cbor2-5.6.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:e3ec251db32516d383fc587874b15f4b5fb4e9049d9436b8696f5767b11c149b"}, - {file = "cbor2-5.6.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:6081c1ab9791d5973a40b95ecb8b04b0fbf9fc04be170d89a3ad77d5964f52d5"}, - {file = "cbor2-5.6.3-cp39-cp39-win_amd64.whl", hash = "sha256:2aba8b75e36c9f84a42a7026271da8fd759035a871c1b799028439059527276b"}, - {file = "cbor2-5.6.3-py3-none-any.whl", hash = "sha256:8a4b7404af6da719092a4ee5953d1930d095b93b684bf99e1ab74512be1910a4"}, - {file = "cbor2-5.6.3.tar.gz", hash = "sha256:e6f0ae2751c2d333a960e0807c0611494eb1245631a167965acbc100509455d3"}, + {file = "cbor2-5.6.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c40c68779a363f47a11ded7b189ba16767391d5eae27fac289e7f62b730ae1fc"}, + {file = "cbor2-5.6.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c0625c8d3c487e509458459de99bf052f62eb5d773cc9fc141c6a6ea9367726d"}, + {file = "cbor2-5.6.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:de7137622204168c3a57882f15dd09b5135bda2bcb1cf8b56b58d26b5150dfca"}, + {file = "cbor2-5.6.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e3545e1e62ec48944b81da2c0e0a736ca98b9e4653c2365cae2f10ae871e9113"}, + {file = "cbor2-5.6.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:d6749913cd00a24eba17406a0bfc872044036c30a37eb2fcde7acfd975317e8a"}, + {file = "cbor2-5.6.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:57db966ab08443ee54b6f154f72021a41bfecd4ba897fe108728183ad8784a2a"}, + {file = "cbor2-5.6.4-cp310-cp310-win_amd64.whl", hash = "sha256:380e0c7f4db574dcd86e6eee1b0041863b0aae7efd449d49b0b784cf9a481b9b"}, + {file = "cbor2-5.6.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5c763d50a1714e0356b90ad39194fc8ef319356b89fb001667a2e836bfde88e3"}, + {file = "cbor2-5.6.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:58a7ac8861857a9f9b0de320a4808a2a5f68a2599b4c14863e2748d5a4686c99"}, + {file = "cbor2-5.6.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7d715b2f101730335e84a25fe0893e2b6adf049d6d44da123bf243b8c875ffd8"}, + {file = "cbor2-5.6.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3f53a67600038cb9668720b309fdfafa8c16d1a02570b96d2144d58d66774318"}, + {file = "cbor2-5.6.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:f898bab20c4f42dca3688c673ff97c2f719b1811090430173c94452603fbcf13"}, + {file = "cbor2-5.6.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:5e5d50fb9f47d295c1b7f55592111350424283aff4cc88766c656aad0300f11f"}, + {file = "cbor2-5.6.4-cp311-cp311-win_amd64.whl", hash = "sha256:7f9d867dcd814ab8383ad132eb4063e2b69f6a9f688797b7a8ca34a4eadb3944"}, + {file = "cbor2-5.6.4-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:e0860ca88edf8aaec5461ce0e498eb5318f1bcc70d93f90091b7a1f1d351a167"}, + {file = "cbor2-5.6.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:c38a0ed495a63a8bef6400158746a9cb03c36f89aeed699be7ffebf82720bf86"}, + {file = "cbor2-5.6.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0c8d8c2f208c223a61bed48dfd0661694b891e423094ed30bac2ed75032142aa"}, + {file = "cbor2-5.6.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:24cd2ce6136e1985da989e5ba572521023a320dcefad5d1fff57fba261de80ca"}, + {file = "cbor2-5.6.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:7facce04aed2bf69ef43bdffb725446fe243594c2451921e89cc305bede16f02"}, + {file = "cbor2-5.6.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:f9c8ee0d89411e5e039a4f3419befe8b43c0dd8746eedc979e73f4c06fe0ef97"}, + {file = "cbor2-5.6.4-cp312-cp312-win_amd64.whl", hash = "sha256:9b45d554daa540e2f29f1747df9f08f8d98ade65a67b1911791bc193d33a5923"}, + {file = "cbor2-5.6.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0a5cb2c16687ccd76b38cfbfdb34468ab7d5635fb92c9dc5e07831c1816bd0a9"}, + {file = "cbor2-5.6.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:6f985f531f7495527153c4f66c8c143e4cf8a658ec9e87b14bc5438e0a8d0911"}, + {file = "cbor2-5.6.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a9d9c7b4bd7c3ea7e5587d4f1bbe073b81719530ddadb999b184074f064896e2"}, + {file = "cbor2-5.6.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:64d06184dcdc275c389fee3cd0ea80b5e1769763df15f93ecd0bf4c281817365"}, + {file = "cbor2-5.6.4-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:e9ba7116f201860fb4c3e80ef36be63851ec7e4a18af70fea22d09cab0b000bf"}, + {file = "cbor2-5.6.4-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:341468ae58bdedaa05c907ab16e90dd0d5c54d7d1e66698dfacdbc16a31e815b"}, + {file = "cbor2-5.6.4-cp38-cp38-win_amd64.whl", hash = "sha256:bcb4994be1afcc81f9167c220645d878b608cae92e19f6706e770f9bc7bbff6c"}, + {file = "cbor2-5.6.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:41c43abffe217dce70ae51c7086530687670a0995dfc90cc35f32f2cf4d86392"}, + {file = "cbor2-5.6.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:227a7e68ba378fe53741ed892b5b03fe472b5bd23ef26230a71964accebf50a2"}, + {file = "cbor2-5.6.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:13521b7c9a0551fcc812d36afd03fc554fa4e1b193659bb5d4d521889aa81154"}, + {file = "cbor2-5.6.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6f4816d290535d20c7b7e2663b76da5b0deb4237b90275c202c26343d8852b8a"}, + {file = "cbor2-5.6.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:1e98d370106821335efcc8fbe4136ea26b4747bf29ca0e66512b6c4f6f5cc59f"}, + {file = "cbor2-5.6.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:68743a18e16167ff37654a29321f64f0441801dba68359c82dc48173cc6c87e1"}, + {file = "cbor2-5.6.4-cp39-cp39-win_amd64.whl", hash = "sha256:7ba5e9c6ed17526d266a1116c045c0941f710860c5f2495758df2e0d848c1b6d"}, + {file = "cbor2-5.6.4-py3-none-any.whl", hash = "sha256:fe411c4bf464f5976605103ebcd0f60b893ac3e4c7c8d8bc8f4a0cb456e33c60"}, + {file = "cbor2-5.6.4.tar.gz", hash = "sha256:1c533c50dde86bef1c6950602054a0ffa3c376e8b0e20c7b8f5b108793f6983e"}, ] [package.extras] @@ -193,13 +222,13 @@ test = ["coverage (>=7)", "hypothesis", "pytest"] [[package]] name = "certifi" -version = "2024.2.2" +version = "2024.8.30" description = "Python package for providing Mozilla's CA Bundle." optional = false python-versions = ">=3.6" files = [ - {file = "certifi-2024.2.2-py3-none-any.whl", hash = "sha256:dc383c07b76109f368f6106eee2b593b04a011ea4d55f652c6ca24a754d1cdd1"}, - {file = "certifi-2024.2.2.tar.gz", hash = "sha256:0569859f95fc761b18b45ef421b1290a0f65f147e92a1e5eb3e635f9a5e4e66f"}, + {file = "certifi-2024.8.30-py3-none-any.whl", hash = "sha256:922820b53db7a7257ffbda3f597266d435245903d80737e34f8a45ff3e3230d8"}, + {file = "certifi-2024.8.30.tar.gz", hash = "sha256:bec941d2aa8195e248a60b31ff9f0558284cf01a52591ceda73ea9afffd69fd9"}, ] [[package]] @@ -219,63 +248,78 @@ oscrypto = ">=0.16.1" [[package]] name = "cffi" -version = "1.16.0" +version = "1.17.1" description = "Foreign Function Interface for Python calling C code." optional = false python-versions = ">=3.8" files = [ - {file = "cffi-1.16.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6b3d6606d369fc1da4fd8c357d026317fbb9c9b75d36dc16e90e84c26854b088"}, - {file = "cffi-1.16.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ac0f5edd2360eea2f1daa9e26a41db02dd4b0451b48f7c318e217ee092a213e9"}, - {file = "cffi-1.16.0-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7e61e3e4fa664a8588aa25c883eab612a188c725755afff6289454d6362b9673"}, - {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a72e8961a86d19bdb45851d8f1f08b041ea37d2bd8d4fd19903bc3083d80c896"}, - {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5b50bf3f55561dac5438f8e70bfcdfd74543fd60df5fa5f62d94e5867deca684"}, - {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7651c50c8c5ef7bdb41108b7b8c5a83013bfaa8a935590c5d74627c047a583c7"}, - {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e4108df7fe9b707191e55f33efbcb2d81928e10cea45527879a4749cbe472614"}, - {file = "cffi-1.16.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:32c68ef735dbe5857c810328cb2481e24722a59a2003018885514d4c09af9743"}, - {file = "cffi-1.16.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:673739cb539f8cdaa07d92d02efa93c9ccf87e345b9a0b556e3ecc666718468d"}, - {file = "cffi-1.16.0-cp310-cp310-win32.whl", hash = "sha256:9f90389693731ff1f659e55c7d1640e2ec43ff725cc61b04b2f9c6d8d017df6a"}, - {file = "cffi-1.16.0-cp310-cp310-win_amd64.whl", hash = "sha256:e6024675e67af929088fda399b2094574609396b1decb609c55fa58b028a32a1"}, - {file = "cffi-1.16.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b84834d0cf97e7d27dd5b7f3aca7b6e9263c56308ab9dc8aae9784abb774d404"}, - {file = "cffi-1.16.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1b8ebc27c014c59692bb2664c7d13ce7a6e9a629be20e54e7271fa696ff2b417"}, - {file = "cffi-1.16.0-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ee07e47c12890ef248766a6e55bd38ebfb2bb8edd4142d56db91b21ea68b7627"}, - {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8a9d3ebe49f084ad71f9269834ceccbf398253c9fac910c4fd7053ff1386936"}, - {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e70f54f1796669ef691ca07d046cd81a29cb4deb1e5f942003f401c0c4a2695d"}, - {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5bf44d66cdf9e893637896c7faa22298baebcd18d1ddb6d2626a6e39793a1d56"}, - {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7b78010e7b97fef4bee1e896df8a4bbb6712b7f05b7ef630f9d1da00f6444d2e"}, - {file = "cffi-1.16.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:c6a164aa47843fb1b01e941d385aab7215563bb8816d80ff3a363a9f8448a8dc"}, - {file = "cffi-1.16.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e09f3ff613345df5e8c3667da1d918f9149bd623cd9070c983c013792a9a62eb"}, - {file = "cffi-1.16.0-cp311-cp311-win32.whl", hash = "sha256:2c56b361916f390cd758a57f2e16233eb4f64bcbeee88a4881ea90fca14dc6ab"}, - {file = "cffi-1.16.0-cp311-cp311-win_amd64.whl", hash = "sha256:db8e577c19c0fda0beb7e0d4e09e0ba74b1e4c092e0e40bfa12fe05b6f6d75ba"}, - {file = "cffi-1.16.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:fa3a0128b152627161ce47201262d3140edb5a5c3da88d73a1b790a959126956"}, - {file = "cffi-1.16.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:68e7c44931cc171c54ccb702482e9fc723192e88d25a0e133edd7aff8fcd1f6e"}, - {file = "cffi-1.16.0-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:abd808f9c129ba2beda4cfc53bde801e5bcf9d6e0f22f095e45327c038bfe68e"}, - {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:88e2b3c14bdb32e440be531ade29d3c50a1a59cd4e51b1dd8b0865c54ea5d2e2"}, - {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fcc8eb6d5902bb1cf6dc4f187ee3ea80a1eba0a89aba40a5cb20a5087d961357"}, - {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b7be2d771cdba2942e13215c4e340bfd76398e9227ad10402a8767ab1865d2e6"}, - {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e715596e683d2ce000574bae5d07bd522c781a822866c20495e52520564f0969"}, - {file = "cffi-1.16.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:2d92b25dbf6cae33f65005baf472d2c245c050b1ce709cc4588cdcdd5495b520"}, - {file = "cffi-1.16.0-cp312-cp312-win32.whl", hash = "sha256:b2ca4e77f9f47c55c194982e10f058db063937845bb2b7a86c84a6cfe0aefa8b"}, - {file = "cffi-1.16.0-cp312-cp312-win_amd64.whl", hash = "sha256:68678abf380b42ce21a5f2abde8efee05c114c2fdb2e9eef2efdb0257fba1235"}, - {file = "cffi-1.16.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0c9ef6ff37e974b73c25eecc13952c55bceed9112be2d9d938ded8e856138bcc"}, - {file = "cffi-1.16.0-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a09582f178759ee8128d9270cd1344154fd473bb77d94ce0aeb2a93ebf0feaf0"}, - {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e760191dd42581e023a68b758769e2da259b5d52e3103c6060ddc02c9edb8d7b"}, - {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:80876338e19c951fdfed6198e70bc88f1c9758b94578d5a7c4c91a87af3cf31c"}, - {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a6a14b17d7e17fa0d207ac08642c8820f84f25ce17a442fd15e27ea18d67c59b"}, - {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6602bc8dc6f3a9e02b6c22c4fc1e47aa50f8f8e6d3f78a5e16ac33ef5fefa324"}, - {file = "cffi-1.16.0-cp38-cp38-win32.whl", hash = "sha256:131fd094d1065b19540c3d72594260f118b231090295d8c34e19a7bbcf2e860a"}, - {file = "cffi-1.16.0-cp38-cp38-win_amd64.whl", hash = "sha256:31d13b0f99e0836b7ff893d37af07366ebc90b678b6664c955b54561fc36ef36"}, - {file = "cffi-1.16.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:582215a0e9adbe0e379761260553ba11c58943e4bbe9c36430c4ca6ac74b15ed"}, - {file = "cffi-1.16.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b29ebffcf550f9da55bec9e02ad430c992a87e5f512cd63388abb76f1036d8d2"}, - {file = "cffi-1.16.0-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dc9b18bf40cc75f66f40a7379f6a9513244fe33c0e8aa72e2d56b0196a7ef872"}, - {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9cb4a35b3642fc5c005a6755a5d17c6c8b6bcb6981baf81cea8bfbc8903e8ba8"}, - {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b86851a328eedc692acf81fb05444bdf1891747c25af7529e39ddafaf68a4f3f"}, - {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c0f31130ebc2d37cdd8e44605fb5fa7ad59049298b3f745c74fa74c62fbfcfc4"}, - {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f8e709127c6c77446a8c0a8c8bf3c8ee706a06cd44b1e827c3e6a2ee6b8c098"}, - {file = "cffi-1.16.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:748dcd1e3d3d7cd5443ef03ce8685043294ad6bd7c02a38d1bd367cfd968e000"}, - {file = "cffi-1.16.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8895613bcc094d4a1b2dbe179d88d7fb4a15cee43c052e8885783fac397d91fe"}, - {file = "cffi-1.16.0-cp39-cp39-win32.whl", hash = "sha256:ed86a35631f7bfbb28e108dd96773b9d5a6ce4811cf6ea468bb6a359b256b1e4"}, - {file = "cffi-1.16.0-cp39-cp39-win_amd64.whl", hash = "sha256:3686dffb02459559c74dd3d81748269ffb0eb027c39a6fc99502de37d501faa8"}, - {file = "cffi-1.16.0.tar.gz", hash = "sha256:bcb3ef43e58665bbda2fb198698fcae6776483e0c4a631aa5647806c25e02cc0"}, + {file = "cffi-1.17.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:df8b1c11f177bc2313ec4b2d46baec87a5f3e71fc8b45dab2ee7cae86d9aba14"}, + {file = "cffi-1.17.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8f2cdc858323644ab277e9bb925ad72ae0e67f69e804f4898c070998d50b1a67"}, + {file = "cffi-1.17.1-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:edae79245293e15384b51f88b00613ba9f7198016a5948b5dddf4917d4d26382"}, + {file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:45398b671ac6d70e67da8e4224a065cec6a93541bb7aebe1b198a61b58c7b702"}, + {file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ad9413ccdeda48c5afdae7e4fa2192157e991ff761e7ab8fdd8926f40b160cc3"}, + {file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5da5719280082ac6bd9aa7becb3938dc9f9cbd57fac7d2871717b1feb0902ab6"}, + {file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2bb1a08b8008b281856e5971307cc386a8e9c5b625ac297e853d36da6efe9c17"}, + {file = "cffi-1.17.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:045d61c734659cc045141be4bae381a41d89b741f795af1dd018bfb532fd0df8"}, + {file = "cffi-1.17.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:6883e737d7d9e4899a8a695e00ec36bd4e5e4f18fabe0aca0efe0a4b44cdb13e"}, + {file = "cffi-1.17.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:6b8b4a92e1c65048ff98cfe1f735ef8f1ceb72e3d5f0c25fdb12087a23da22be"}, + {file = "cffi-1.17.1-cp310-cp310-win32.whl", hash = "sha256:c9c3d058ebabb74db66e431095118094d06abf53284d9c81f27300d0e0d8bc7c"}, + {file = "cffi-1.17.1-cp310-cp310-win_amd64.whl", hash = "sha256:0f048dcf80db46f0098ccac01132761580d28e28bc0f78ae0d58048063317e15"}, + {file = "cffi-1.17.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a45e3c6913c5b87b3ff120dcdc03f6131fa0065027d0ed7ee6190736a74cd401"}, + {file = "cffi-1.17.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:30c5e0cb5ae493c04c8b42916e52ca38079f1b235c2f8ae5f4527b963c401caf"}, + {file = "cffi-1.17.1-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f75c7ab1f9e4aca5414ed4d8e5c0e303a34f4421f8a0d47a4d019ceff0ab6af4"}, + {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a1ed2dd2972641495a3ec98445e09766f077aee98a1c896dcb4ad0d303628e41"}, + {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:46bf43160c1a35f7ec506d254e5c890f3c03648a4dbac12d624e4490a7046cd1"}, + {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a24ed04c8ffd54b0729c07cee15a81d964e6fee0e3d4d342a27b020d22959dc6"}, + {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:610faea79c43e44c71e1ec53a554553fa22321b65fae24889706c0a84d4ad86d"}, + {file = "cffi-1.17.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:a9b15d491f3ad5d692e11f6b71f7857e7835eb677955c00cc0aefcd0669adaf6"}, + {file = "cffi-1.17.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:de2ea4b5833625383e464549fec1bc395c1bdeeb5f25c4a3a82b5a8c756ec22f"}, + {file = "cffi-1.17.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:fc48c783f9c87e60831201f2cce7f3b2e4846bf4d8728eabe54d60700b318a0b"}, + {file = "cffi-1.17.1-cp311-cp311-win32.whl", hash = "sha256:85a950a4ac9c359340d5963966e3e0a94a676bd6245a4b55bc43949eee26a655"}, + {file = "cffi-1.17.1-cp311-cp311-win_amd64.whl", hash = "sha256:caaf0640ef5f5517f49bc275eca1406b0ffa6aa184892812030f04c2abf589a0"}, + {file = "cffi-1.17.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:805b4371bf7197c329fcb3ead37e710d1bca9da5d583f5073b799d5c5bd1eee4"}, + {file = "cffi-1.17.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:733e99bc2df47476e3848417c5a4540522f234dfd4ef3ab7fafdf555b082ec0c"}, + {file = "cffi-1.17.1-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1257bdabf294dceb59f5e70c64a3e2f462c30c7ad68092d01bbbfb1c16b1ba36"}, + {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da95af8214998d77a98cc14e3a3bd00aa191526343078b530ceb0bd710fb48a5"}, + {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d63afe322132c194cf832bfec0dc69a99fb9bb6bbd550f161a49e9e855cc78ff"}, + {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f79fc4fc25f1c8698ff97788206bb3c2598949bfe0fef03d299eb1b5356ada99"}, + {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b62ce867176a75d03a665bad002af8e6d54644fad99a3c70905c543130e39d93"}, + {file = "cffi-1.17.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:386c8bf53c502fff58903061338ce4f4950cbdcb23e2902d86c0f722b786bbe3"}, + {file = "cffi-1.17.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4ceb10419a9adf4460ea14cfd6bc43d08701f0835e979bf821052f1805850fe8"}, + {file = "cffi-1.17.1-cp312-cp312-win32.whl", hash = "sha256:a08d7e755f8ed21095a310a693525137cfe756ce62d066e53f502a83dc550f65"}, + {file = "cffi-1.17.1-cp312-cp312-win_amd64.whl", hash = "sha256:51392eae71afec0d0c8fb1a53b204dbb3bcabcb3c9b807eedf3e1e6ccf2de903"}, + {file = "cffi-1.17.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f3a2b4222ce6b60e2e8b337bb9596923045681d71e5a082783484d845390938e"}, + {file = "cffi-1.17.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0984a4925a435b1da406122d4d7968dd861c1385afe3b45ba82b750f229811e2"}, + {file = "cffi-1.17.1-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d01b12eeeb4427d3110de311e1774046ad344f5b1a7403101878976ecd7a10f3"}, + {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:706510fe141c86a69c8ddc029c7910003a17353970cff3b904ff0686a5927683"}, + {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:de55b766c7aa2e2a3092c51e0483d700341182f08e67c63630d5b6f200bb28e5"}, + {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c59d6e989d07460165cc5ad3c61f9fd8f1b4796eacbd81cee78957842b834af4"}, + {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd398dbc6773384a17fe0d3e7eeb8d1a21c2200473ee6806bb5e6a8e62bb73dd"}, + {file = "cffi-1.17.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:3edc8d958eb099c634dace3c7e16560ae474aa3803a5df240542b305d14e14ed"}, + {file = "cffi-1.17.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:72e72408cad3d5419375fc87d289076ee319835bdfa2caad331e377589aebba9"}, + {file = "cffi-1.17.1-cp313-cp313-win32.whl", hash = "sha256:e03eab0a8677fa80d646b5ddece1cbeaf556c313dcfac435ba11f107ba117b5d"}, + {file = "cffi-1.17.1-cp313-cp313-win_amd64.whl", hash = "sha256:f6a16c31041f09ead72d69f583767292f750d24913dadacf5756b966aacb3f1a"}, + {file = "cffi-1.17.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:636062ea65bd0195bc012fea9321aca499c0504409f413dc88af450b57ffd03b"}, + {file = "cffi-1.17.1-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c7eac2ef9b63c79431bc4b25f1cd649d7f061a28808cbc6c47b534bd789ef964"}, + {file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e221cf152cff04059d011ee126477f0d9588303eb57e88923578ace7baad17f9"}, + {file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:31000ec67d4221a71bd3f67df918b1f88f676f1c3b535a7eb473255fdc0b83fc"}, + {file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6f17be4345073b0a7b8ea599688f692ac3ef23ce28e5df79c04de519dbc4912c"}, + {file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0e2b1fac190ae3ebfe37b979cc1ce69c81f4e4fe5746bb401dca63a9062cdaf1"}, + {file = "cffi-1.17.1-cp38-cp38-win32.whl", hash = "sha256:7596d6620d3fa590f677e9ee430df2958d2d6d6de2feeae5b20e82c00b76fbf8"}, + {file = "cffi-1.17.1-cp38-cp38-win_amd64.whl", hash = "sha256:78122be759c3f8a014ce010908ae03364d00a1f81ab5c7f4a7a5120607ea56e1"}, + {file = "cffi-1.17.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b2ab587605f4ba0bf81dc0cb08a41bd1c0a5906bd59243d56bad7668a6fc6c16"}, + {file = "cffi-1.17.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:28b16024becceed8c6dfbc75629e27788d8a3f9030691a1dbf9821a128b22c36"}, + {file = "cffi-1.17.1-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1d599671f396c4723d016dbddb72fe8e0397082b0a77a4fab8028923bec050e8"}, + {file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ca74b8dbe6e8e8263c0ffd60277de77dcee6c837a3d0881d8c1ead7268c9e576"}, + {file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f7f5baafcc48261359e14bcd6d9bff6d4b28d9103847c9e136694cb0501aef87"}, + {file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:98e3969bcff97cae1b2def8ba499ea3d6f31ddfdb7635374834cf89a1a08ecf0"}, + {file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cdf5ce3acdfd1661132f2a9c19cac174758dc2352bfe37d98aa7512c6b7178b3"}, + {file = "cffi-1.17.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:9755e4345d1ec879e3849e62222a18c7174d65a6a92d5b346b1863912168b595"}, + {file = "cffi-1.17.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:f1e22e8c4419538cb197e4dd60acc919d7696e5ef98ee4da4e01d3f8cfa4cc5a"}, + {file = "cffi-1.17.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:c03e868a0b3bc35839ba98e74211ed2b05d2119be4e8a0f224fba9384f1fe02e"}, + {file = "cffi-1.17.1-cp39-cp39-win32.whl", hash = "sha256:e31ae45bc2e29f6b2abd0de1cc3b9d5205aa847cafaecb8af1476a609a2f6eb7"}, + {file = "cffi-1.17.1-cp39-cp39-win_amd64.whl", hash = "sha256:d016c76bdd850f3c626af19b0542c9677ba156e4ee4fccfdd7848803533ef662"}, + {file = "cffi-1.17.1.tar.gz", hash = "sha256:1c39c6016c32bc48dd54561950ebd6836e1670f2ae46128f67cf49e789c52824"}, ] [package.dependencies] @@ -405,6 +449,23 @@ files = [ {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, ] +[[package]] +name = "coloredlogs" +version = "15.0.1" +description = "Colored terminal output for Python's logging module" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +files = [ + {file = "coloredlogs-15.0.1-py2.py3-none-any.whl", hash = "sha256:612ee75c546f53e92e70049c9dbfcc18c935a2b9a53b66085ce9ef6a6e5c0934"}, + {file = "coloredlogs-15.0.1.tar.gz", hash = "sha256:7c991aa71a4577af2f82600d8f8f3a89f936baeaf9b50a9c197da014e5bf16b0"}, +] + +[package.dependencies] +humanfriendly = ">=9.1" + +[package.extras] +cron = ["capturer (>=2.4)"] + [[package]] name = "cose" version = "0.9.dev8" @@ -425,63 +486,83 @@ ecdsa = "*" [[package]] name = "coverage" -version = "7.5.3" +version = "7.6.1" description = "Code coverage measurement for Python" optional = false python-versions = ">=3.8" files = [ - {file = "coverage-7.5.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:a6519d917abb15e12380406d721e37613e2a67d166f9fb7e5a8ce0375744cd45"}, - {file = "coverage-7.5.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:aea7da970f1feccf48be7335f8b2ca64baf9b589d79e05b9397a06696ce1a1ec"}, - {file = "coverage-7.5.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:923b7b1c717bd0f0f92d862d1ff51d9b2b55dbbd133e05680204465f454bb286"}, - {file = "coverage-7.5.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:62bda40da1e68898186f274f832ef3e759ce929da9a9fd9fcf265956de269dbc"}, - {file = "coverage-7.5.3-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d8b7339180d00de83e930358223c617cc343dd08e1aa5ec7b06c3a121aec4e1d"}, - {file = "coverage-7.5.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:25a5caf742c6195e08002d3b6c2dd6947e50efc5fc2c2205f61ecb47592d2d83"}, - {file = "coverage-7.5.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:05ac5f60faa0c704c0f7e6a5cbfd6f02101ed05e0aee4d2822637a9e672c998d"}, - {file = "coverage-7.5.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:239a4e75e09c2b12ea478d28815acf83334d32e722e7433471fbf641c606344c"}, - {file = "coverage-7.5.3-cp310-cp310-win32.whl", hash = "sha256:a5812840d1d00eafae6585aba38021f90a705a25b8216ec7f66aebe5b619fb84"}, - {file = "coverage-7.5.3-cp310-cp310-win_amd64.whl", hash = "sha256:33ca90a0eb29225f195e30684ba4a6db05dbef03c2ccd50b9077714c48153cac"}, - {file = "coverage-7.5.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f81bc26d609bf0fbc622c7122ba6307993c83c795d2d6f6f6fd8c000a770d974"}, - {file = "coverage-7.5.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7cec2af81f9e7569280822be68bd57e51b86d42e59ea30d10ebdbb22d2cb7232"}, - {file = "coverage-7.5.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:55f689f846661e3f26efa535071775d0483388a1ccfab899df72924805e9e7cd"}, - {file = "coverage-7.5.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:50084d3516aa263791198913a17354bd1dc627d3c1639209640b9cac3fef5807"}, - {file = "coverage-7.5.3-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:341dd8f61c26337c37988345ca5c8ccabeff33093a26953a1ac72e7d0103c4fb"}, - {file = "coverage-7.5.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ab0b028165eea880af12f66086694768f2c3139b2c31ad5e032c8edbafca6ffc"}, - {file = "coverage-7.5.3-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:5bc5a8c87714b0c67cfeb4c7caa82b2d71e8864d1a46aa990b5588fa953673b8"}, - {file = "coverage-7.5.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:38a3b98dae8a7c9057bd91fbf3415c05e700a5114c5f1b5b0ea5f8f429ba6614"}, - {file = "coverage-7.5.3-cp311-cp311-win32.whl", hash = "sha256:fcf7d1d6f5da887ca04302db8e0e0cf56ce9a5e05f202720e49b3e8157ddb9a9"}, - {file = "coverage-7.5.3-cp311-cp311-win_amd64.whl", hash = "sha256:8c836309931839cca658a78a888dab9676b5c988d0dd34ca247f5f3e679f4e7a"}, - {file = "coverage-7.5.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:296a7d9bbc598e8744c00f7a6cecf1da9b30ae9ad51c566291ff1314e6cbbed8"}, - {file = "coverage-7.5.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:34d6d21d8795a97b14d503dcaf74226ae51eb1f2bd41015d3ef332a24d0a17b3"}, - {file = "coverage-7.5.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8e317953bb4c074c06c798a11dbdd2cf9979dbcaa8ccc0fa4701d80042d4ebf1"}, - {file = "coverage-7.5.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:705f3d7c2b098c40f5b81790a5fedb274113373d4d1a69e65f8b68b0cc26f6db"}, - {file = "coverage-7.5.3-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b1196e13c45e327d6cd0b6e471530a1882f1017eb83c6229fc613cd1a11b53cd"}, - {file = "coverage-7.5.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:015eddc5ccd5364dcb902eaecf9515636806fa1e0d5bef5769d06d0f31b54523"}, - {file = "coverage-7.5.3-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:fd27d8b49e574e50caa65196d908f80e4dff64d7e592d0c59788b45aad7e8b35"}, - {file = "coverage-7.5.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:33fc65740267222fc02975c061eb7167185fef4cc8f2770267ee8bf7d6a42f84"}, - {file = "coverage-7.5.3-cp312-cp312-win32.whl", hash = "sha256:7b2a19e13dfb5c8e145c7a6ea959485ee8e2204699903c88c7d25283584bfc08"}, - {file = "coverage-7.5.3-cp312-cp312-win_amd64.whl", hash = "sha256:0bbddc54bbacfc09b3edaec644d4ac90c08ee8ed4844b0f86227dcda2d428fcb"}, - {file = "coverage-7.5.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:f78300789a708ac1f17e134593f577407d52d0417305435b134805c4fb135adb"}, - {file = "coverage-7.5.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:b368e1aee1b9b75757942d44d7598dcd22a9dbb126affcbba82d15917f0cc155"}, - {file = "coverage-7.5.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f836c174c3a7f639bded48ec913f348c4761cbf49de4a20a956d3431a7c9cb24"}, - {file = "coverage-7.5.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:244f509f126dc71369393ce5fea17c0592c40ee44e607b6d855e9c4ac57aac98"}, - {file = "coverage-7.5.3-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c4c2872b3c91f9baa836147ca33650dc5c172e9273c808c3c3199c75490e709d"}, - {file = "coverage-7.5.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:dd4b3355b01273a56b20c219e74e7549e14370b31a4ffe42706a8cda91f19f6d"}, - {file = "coverage-7.5.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:f542287b1489c7a860d43a7d8883e27ca62ab84ca53c965d11dac1d3a1fab7ce"}, - {file = "coverage-7.5.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:75e3f4e86804023e991096b29e147e635f5e2568f77883a1e6eed74512659ab0"}, - {file = "coverage-7.5.3-cp38-cp38-win32.whl", hash = "sha256:c59d2ad092dc0551d9f79d9d44d005c945ba95832a6798f98f9216ede3d5f485"}, - {file = "coverage-7.5.3-cp38-cp38-win_amd64.whl", hash = "sha256:fa21a04112c59ad54f69d80e376f7f9d0f5f9123ab87ecd18fbb9ec3a2beed56"}, - {file = "coverage-7.5.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f5102a92855d518b0996eb197772f5ac2a527c0ec617124ad5242a3af5e25f85"}, - {file = "coverage-7.5.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:d1da0a2e3b37b745a2b2a678a4c796462cf753aebf94edcc87dcc6b8641eae31"}, - {file = "coverage-7.5.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8383a6c8cefba1b7cecc0149415046b6fc38836295bc4c84e820872eb5478b3d"}, - {file = "coverage-7.5.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9aad68c3f2566dfae84bf46295a79e79d904e1c21ccfc66de88cd446f8686341"}, - {file = "coverage-7.5.3-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2e079c9ec772fedbade9d7ebc36202a1d9ef7291bc9b3a024ca395c4d52853d7"}, - {file = "coverage-7.5.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:bde997cac85fcac227b27d4fb2c7608a2c5f6558469b0eb704c5726ae49e1c52"}, - {file = "coverage-7.5.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:990fb20b32990b2ce2c5f974c3e738c9358b2735bc05075d50a6f36721b8f303"}, - {file = "coverage-7.5.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:3d5a67f0da401e105753d474369ab034c7bae51a4c31c77d94030d59e41df5bd"}, - {file = "coverage-7.5.3-cp39-cp39-win32.whl", hash = "sha256:e08c470c2eb01977d221fd87495b44867a56d4d594f43739a8028f8646a51e0d"}, - {file = "coverage-7.5.3-cp39-cp39-win_amd64.whl", hash = "sha256:1d2a830ade66d3563bb61d1e3c77c8def97b30ed91e166c67d0632c018f380f0"}, - {file = "coverage-7.5.3-pp38.pp39.pp310-none-any.whl", hash = "sha256:3538d8fb1ee9bdd2e2692b3b18c22bb1c19ffbefd06880f5ac496e42d7bb3884"}, - {file = "coverage-7.5.3.tar.gz", hash = "sha256:04aefca5190d1dc7a53a4c1a5a7f8568811306d7a8ee231c42fb69215571944f"}, + {file = "coverage-7.6.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b06079abebbc0e89e6163b8e8f0e16270124c154dc6e4a47b413dd538859af16"}, + {file = "coverage-7.6.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:cf4b19715bccd7ee27b6b120e7e9dd56037b9c0681dcc1adc9ba9db3d417fa36"}, + {file = "coverage-7.6.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e61c0abb4c85b095a784ef23fdd4aede7a2628478e7baba7c5e3deba61070a02"}, + {file = "coverage-7.6.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fd21f6ae3f08b41004dfb433fa895d858f3f5979e7762d052b12aef444e29afc"}, + {file = "coverage-7.6.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f59d57baca39b32db42b83b2a7ba6f47ad9c394ec2076b084c3f029b7afca23"}, + {file = "coverage-7.6.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:a1ac0ae2b8bd743b88ed0502544847c3053d7171a3cff9228af618a068ed9c34"}, + {file = "coverage-7.6.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e6a08c0be454c3b3beb105c0596ebdc2371fab6bb90c0c0297f4e58fd7e1012c"}, + {file = "coverage-7.6.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:f5796e664fe802da4f57a168c85359a8fbf3eab5e55cd4e4569fbacecc903959"}, + {file = "coverage-7.6.1-cp310-cp310-win32.whl", hash = "sha256:7bb65125fcbef8d989fa1dd0e8a060999497629ca5b0efbca209588a73356232"}, + {file = "coverage-7.6.1-cp310-cp310-win_amd64.whl", hash = "sha256:3115a95daa9bdba70aea750db7b96b37259a81a709223c8448fa97727d546fe0"}, + {file = "coverage-7.6.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:7dea0889685db8550f839fa202744652e87c60015029ce3f60e006f8c4462c93"}, + {file = "coverage-7.6.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ed37bd3c3b063412f7620464a9ac1314d33100329f39799255fb8d3027da50d3"}, + {file = "coverage-7.6.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d85f5e9a5f8b73e2350097c3756ef7e785f55bd71205defa0bfdaf96c31616ff"}, + {file = "coverage-7.6.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9bc572be474cafb617672c43fe989d6e48d3c83af02ce8de73fff1c6bb3c198d"}, + {file = "coverage-7.6.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0c0420b573964c760df9e9e86d1a9a622d0d27f417e1a949a8a66dd7bcee7bc6"}, + {file = "coverage-7.6.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1f4aa8219db826ce6be7099d559f8ec311549bfc4046f7f9fe9b5cea5c581c56"}, + {file = "coverage-7.6.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:fc5a77d0c516700ebad189b587de289a20a78324bc54baee03dd486f0855d234"}, + {file = "coverage-7.6.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b48f312cca9621272ae49008c7f613337c53fadca647d6384cc129d2996d1133"}, + {file = "coverage-7.6.1-cp311-cp311-win32.whl", hash = "sha256:1125ca0e5fd475cbbba3bb67ae20bd2c23a98fac4e32412883f9bcbaa81c314c"}, + {file = "coverage-7.6.1-cp311-cp311-win_amd64.whl", hash = "sha256:8ae539519c4c040c5ffd0632784e21b2f03fc1340752af711f33e5be83a9d6c6"}, + {file = "coverage-7.6.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:95cae0efeb032af8458fc27d191f85d1717b1d4e49f7cb226cf526ff28179778"}, + {file = "coverage-7.6.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5621a9175cf9d0b0c84c2ef2b12e9f5f5071357c4d2ea6ca1cf01814f45d2391"}, + {file = "coverage-7.6.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:260933720fdcd75340e7dbe9060655aff3af1f0c5d20f46b57f262ab6c86a5e8"}, + {file = "coverage-7.6.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:07e2ca0ad381b91350c0ed49d52699b625aab2b44b65e1b4e02fa9df0e92ad2d"}, + {file = "coverage-7.6.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c44fee9975f04b33331cb8eb272827111efc8930cfd582e0320613263ca849ca"}, + {file = "coverage-7.6.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:877abb17e6339d96bf08e7a622d05095e72b71f8afd8a9fefc82cf30ed944163"}, + {file = "coverage-7.6.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:3e0cadcf6733c09154b461f1ca72d5416635e5e4ec4e536192180d34ec160f8a"}, + {file = "coverage-7.6.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:c3c02d12f837d9683e5ab2f3d9844dc57655b92c74e286c262e0fc54213c216d"}, + {file = "coverage-7.6.1-cp312-cp312-win32.whl", hash = "sha256:e05882b70b87a18d937ca6768ff33cc3f72847cbc4de4491c8e73880766718e5"}, + {file = "coverage-7.6.1-cp312-cp312-win_amd64.whl", hash = "sha256:b5d7b556859dd85f3a541db6a4e0167b86e7273e1cdc973e5b175166bb634fdb"}, + {file = "coverage-7.6.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:a4acd025ecc06185ba2b801f2de85546e0b8ac787cf9d3b06e7e2a69f925b106"}, + {file = "coverage-7.6.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a6d3adcf24b624a7b778533480e32434a39ad8fa30c315208f6d3e5542aeb6e9"}, + {file = "coverage-7.6.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d0c212c49b6c10e6951362f7c6df3329f04c2b1c28499563d4035d964ab8e08c"}, + {file = "coverage-7.6.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6e81d7a3e58882450ec4186ca59a3f20a5d4440f25b1cff6f0902ad890e6748a"}, + {file = "coverage-7.6.1-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:78b260de9790fd81e69401c2dc8b17da47c8038176a79092a89cb2b7d945d060"}, + {file = "coverage-7.6.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a78d169acd38300060b28d600344a803628c3fd585c912cacc9ea8790fe96862"}, + {file = "coverage-7.6.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:2c09f4ce52cb99dd7505cd0fc8e0e37c77b87f46bc9c1eb03fe3bc9991085388"}, + {file = "coverage-7.6.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6878ef48d4227aace338d88c48738a4258213cd7b74fd9a3d4d7582bb1d8a155"}, + {file = "coverage-7.6.1-cp313-cp313-win32.whl", hash = "sha256:44df346d5215a8c0e360307d46ffaabe0f5d3502c8a1cefd700b34baf31d411a"}, + {file = "coverage-7.6.1-cp313-cp313-win_amd64.whl", hash = "sha256:8284cf8c0dd272a247bc154eb6c95548722dce90d098c17a883ed36e67cdb129"}, + {file = "coverage-7.6.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:d3296782ca4eab572a1a4eca686d8bfb00226300dcefdf43faa25b5242ab8a3e"}, + {file = "coverage-7.6.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:502753043567491d3ff6d08629270127e0c31d4184c4c8d98f92c26f65019962"}, + {file = "coverage-7.6.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6a89ecca80709d4076b95f89f308544ec8f7b4727e8a547913a35f16717856cb"}, + {file = "coverage-7.6.1-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a318d68e92e80af8b00fa99609796fdbcdfef3629c77c6283566c6f02c6d6704"}, + {file = "coverage-7.6.1-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:13b0a73a0896988f053e4fbb7de6d93388e6dd292b0d87ee51d106f2c11b465b"}, + {file = "coverage-7.6.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:4421712dbfc5562150f7554f13dde997a2e932a6b5f352edcce948a815efee6f"}, + {file = "coverage-7.6.1-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:166811d20dfea725e2e4baa71fffd6c968a958577848d2131f39b60043400223"}, + {file = "coverage-7.6.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:225667980479a17db1048cb2bf8bfb39b8e5be8f164b8f6628b64f78a72cf9d3"}, + {file = "coverage-7.6.1-cp313-cp313t-win32.whl", hash = "sha256:170d444ab405852903b7d04ea9ae9b98f98ab6d7e63e1115e82620807519797f"}, + {file = "coverage-7.6.1-cp313-cp313t-win_amd64.whl", hash = "sha256:b9f222de8cded79c49bf184bdbc06630d4c58eec9459b939b4a690c82ed05657"}, + {file = "coverage-7.6.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6db04803b6c7291985a761004e9060b2bca08da6d04f26a7f2294b8623a0c1a0"}, + {file = "coverage-7.6.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:f1adfc8ac319e1a348af294106bc6a8458a0f1633cc62a1446aebc30c5fa186a"}, + {file = "coverage-7.6.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a95324a9de9650a729239daea117df21f4b9868ce32e63f8b650ebe6cef5595b"}, + {file = "coverage-7.6.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b43c03669dc4618ec25270b06ecd3ee4fa94c7f9b3c14bae6571ca00ef98b0d3"}, + {file = "coverage-7.6.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8929543a7192c13d177b770008bc4e8119f2e1f881d563fc6b6305d2d0ebe9de"}, + {file = "coverage-7.6.1-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:a09ece4a69cf399510c8ab25e0950d9cf2b42f7b3cb0374f95d2e2ff594478a6"}, + {file = "coverage-7.6.1-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:9054a0754de38d9dbd01a46621636689124d666bad1936d76c0341f7d71bf569"}, + {file = "coverage-7.6.1-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:0dbde0f4aa9a16fa4d754356a8f2e36296ff4d83994b2c9d8398aa32f222f989"}, + {file = "coverage-7.6.1-cp38-cp38-win32.whl", hash = "sha256:da511e6ad4f7323ee5702e6633085fb76c2f893aaf8ce4c51a0ba4fc07580ea7"}, + {file = "coverage-7.6.1-cp38-cp38-win_amd64.whl", hash = "sha256:3f1156e3e8f2872197af3840d8ad307a9dd18e615dc64d9ee41696f287c57ad8"}, + {file = "coverage-7.6.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:abd5fd0db5f4dc9289408aaf34908072f805ff7792632250dcb36dc591d24255"}, + {file = "coverage-7.6.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:547f45fa1a93154bd82050a7f3cddbc1a7a4dd2a9bf5cb7d06f4ae29fe94eaf8"}, + {file = "coverage-7.6.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:645786266c8f18a931b65bfcefdbf6952dd0dea98feee39bd188607a9d307ed2"}, + {file = "coverage-7.6.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9e0b2df163b8ed01d515807af24f63de04bebcecbd6c3bfeff88385789fdf75a"}, + {file = "coverage-7.6.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:609b06f178fe8e9f89ef676532760ec0b4deea15e9969bf754b37f7c40326dbc"}, + {file = "coverage-7.6.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:702855feff378050ae4f741045e19a32d57d19f3e0676d589df0575008ea5004"}, + {file = "coverage-7.6.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:2bdb062ea438f22d99cba0d7829c2ef0af1d768d1e4a4f528087224c90b132cb"}, + {file = "coverage-7.6.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:9c56863d44bd1c4fe2abb8a4d6f5371d197f1ac0ebdee542f07f35895fc07f36"}, + {file = "coverage-7.6.1-cp39-cp39-win32.whl", hash = "sha256:6e2cd258d7d927d09493c8df1ce9174ad01b381d4729a9d8d4e38670ca24774c"}, + {file = "coverage-7.6.1-cp39-cp39-win_amd64.whl", hash = "sha256:06a737c882bd26d0d6ee7269b20b12f14a8704807a01056c80bb881a4b2ce6ca"}, + {file = "coverage-7.6.1-pp38.pp39.pp310-none-any.whl", hash = "sha256:e9a6e0eb86070e8ccaedfbd9d38fec54864f3125ab95419970575b42af7541df"}, + {file = "coverage-7.6.1.tar.gz", hash = "sha256:953510dfb7b12ab69d20135a0662397f077c59b1e6379a768e97c59d852ee51d"}, ] [package.dependencies] @@ -492,43 +573,38 @@ toml = ["tomli"] [[package]] name = "cryptography" -version = "42.0.7" +version = "43.0.1" description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers." optional = false python-versions = ">=3.7" files = [ - {file = "cryptography-42.0.7-cp37-abi3-macosx_10_12_universal2.whl", hash = "sha256:a987f840718078212fdf4504d0fd4c6effe34a7e4740378e59d47696e8dfb477"}, - {file = "cryptography-42.0.7-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:bd13b5e9b543532453de08bcdc3cc7cebec6f9883e886fd20a92f26940fd3e7a"}, - {file = "cryptography-42.0.7-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a79165431551042cc9d1d90e6145d5d0d3ab0f2d66326c201d9b0e7f5bf43604"}, - {file = "cryptography-42.0.7-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a47787a5e3649008a1102d3df55424e86606c9bae6fb77ac59afe06d234605f8"}, - {file = "cryptography-42.0.7-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:02c0eee2d7133bdbbc5e24441258d5d2244beb31da5ed19fbb80315f4bbbff55"}, - {file = "cryptography-42.0.7-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:5e44507bf8d14b36b8389b226665d597bc0f18ea035d75b4e53c7b1ea84583cc"}, - {file = "cryptography-42.0.7-cp37-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:7f8b25fa616d8b846aef64b15c606bb0828dbc35faf90566eb139aa9cff67af2"}, - {file = "cryptography-42.0.7-cp37-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:93a3209f6bb2b33e725ed08ee0991b92976dfdcf4e8b38646540674fc7508e13"}, - {file = "cryptography-42.0.7-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:e6b8f1881dac458c34778d0a424ae5769de30544fc678eac51c1c8bb2183e9da"}, - {file = "cryptography-42.0.7-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:3de9a45d3b2b7d8088c3fbf1ed4395dfeff79d07842217b38df14ef09ce1d8d7"}, - {file = "cryptography-42.0.7-cp37-abi3-win32.whl", hash = "sha256:789caea816c6704f63f6241a519bfa347f72fbd67ba28d04636b7c6b7da94b0b"}, - {file = "cryptography-42.0.7-cp37-abi3-win_amd64.whl", hash = "sha256:8cb8ce7c3347fcf9446f201dc30e2d5a3c898d009126010cbd1f443f28b52678"}, - {file = "cryptography-42.0.7-cp39-abi3-macosx_10_12_universal2.whl", hash = "sha256:a3a5ac8b56fe37f3125e5b72b61dcde43283e5370827f5233893d461b7360cd4"}, - {file = "cryptography-42.0.7-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:779245e13b9a6638df14641d029add5dc17edbef6ec915688f3acb9e720a5858"}, - {file = "cryptography-42.0.7-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0d563795db98b4cd57742a78a288cdbdc9daedac29f2239793071fe114f13785"}, - {file = "cryptography-42.0.7-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:31adb7d06fe4383226c3e963471f6837742889b3c4caa55aac20ad951bc8ffda"}, - {file = "cryptography-42.0.7-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:efd0bf5205240182e0f13bcaea41be4fdf5c22c5129fc7ced4a0282ac86998c9"}, - {file = "cryptography-42.0.7-cp39-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:a9bc127cdc4ecf87a5ea22a2556cab6c7eda2923f84e4f3cc588e8470ce4e42e"}, - {file = "cryptography-42.0.7-cp39-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:3577d029bc3f4827dd5bf8bf7710cac13527b470bbf1820a3f394adb38ed7d5f"}, - {file = "cryptography-42.0.7-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:2e47577f9b18723fa294b0ea9a17d5e53a227867a0a4904a1a076d1646d45ca1"}, - {file = "cryptography-42.0.7-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:1a58839984d9cb34c855197043eaae2c187d930ca6d644612843b4fe8513c886"}, - {file = "cryptography-42.0.7-cp39-abi3-win32.whl", hash = "sha256:e6b79d0adb01aae87e8a44c2b64bc3f3fe59515280e00fb6d57a7267a2583cda"}, - {file = "cryptography-42.0.7-cp39-abi3-win_amd64.whl", hash = "sha256:16268d46086bb8ad5bf0a2b5544d8a9ed87a0e33f5e77dd3c3301e63d941a83b"}, - {file = "cryptography-42.0.7-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:2954fccea107026512b15afb4aa664a5640cd0af630e2ee3962f2602693f0c82"}, - {file = "cryptography-42.0.7-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:362e7197754c231797ec45ee081f3088a27a47c6c01eff2ac83f60f85a50fe60"}, - {file = "cryptography-42.0.7-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:4f698edacf9c9e0371112792558d2f705b5645076cc0aaae02f816a0171770fd"}, - {file = "cryptography-42.0.7-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:5482e789294854c28237bba77c4c83be698be740e31a3ae5e879ee5444166582"}, - {file = "cryptography-42.0.7-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:e9b2a6309f14c0497f348d08a065d52f3020656f675819fc405fb63bbcd26562"}, - {file = "cryptography-42.0.7-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:d8e3098721b84392ee45af2dd554c947c32cc52f862b6a3ae982dbb90f577f14"}, - {file = "cryptography-42.0.7-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:c65f96dad14f8528a447414125e1fc8feb2ad5a272b8f68477abbcc1ea7d94b9"}, - {file = "cryptography-42.0.7-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:36017400817987670037fbb0324d71489b6ead6231c9604f8fc1f7d008087c68"}, - {file = "cryptography-42.0.7.tar.gz", hash = "sha256:ecbfbc00bf55888edda9868a4cf927205de8499e7fabe6c050322298382953f2"}, + {file = "cryptography-43.0.1-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:8385d98f6a3bf8bb2d65a73e17ed87a3ba84f6991c155691c51112075f9ffc5d"}, + {file = "cryptography-43.0.1-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:27e613d7077ac613e399270253259d9d53872aaf657471473ebfc9a52935c062"}, + {file = "cryptography-43.0.1-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:68aaecc4178e90719e95298515979814bda0cbada1256a4485414860bd7ab962"}, + {file = "cryptography-43.0.1-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:de41fd81a41e53267cb020bb3a7212861da53a7d39f863585d13ea11049cf277"}, + {file = "cryptography-43.0.1-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:f98bf604c82c416bc829e490c700ca1553eafdf2912a91e23a79d97d9801372a"}, + {file = "cryptography-43.0.1-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:61ec41068b7b74268fa86e3e9e12b9f0c21fcf65434571dbb13d954bceb08042"}, + {file = "cryptography-43.0.1-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:014f58110f53237ace6a408b5beb6c427b64e084eb451ef25a28308270086494"}, + {file = "cryptography-43.0.1-cp37-abi3-win32.whl", hash = "sha256:2bd51274dcd59f09dd952afb696bf9c61a7a49dfc764c04dd33ef7a6b502a1e2"}, + {file = "cryptography-43.0.1-cp37-abi3-win_amd64.whl", hash = "sha256:666ae11966643886c2987b3b721899d250855718d6d9ce41b521252a17985f4d"}, + {file = "cryptography-43.0.1-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:ac119bb76b9faa00f48128b7f5679e1d8d437365c5d26f1c2c3f0da4ce1b553d"}, + {file = "cryptography-43.0.1-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1bbcce1a551e262dfbafb6e6252f1ae36a248e615ca44ba302df077a846a8806"}, + {file = "cryptography-43.0.1-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:58d4e9129985185a06d849aa6df265bdd5a74ca6e1b736a77959b498e0505b85"}, + {file = "cryptography-43.0.1-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:d03a475165f3134f773d1388aeb19c2d25ba88b6a9733c5c590b9ff7bbfa2e0c"}, + {file = "cryptography-43.0.1-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:511f4273808ab590912a93ddb4e3914dfd8a388fed883361b02dea3791f292e1"}, + {file = "cryptography-43.0.1-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:80eda8b3e173f0f247f711eef62be51b599b5d425c429b5d4ca6a05e9e856baa"}, + {file = "cryptography-43.0.1-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:38926c50cff6f533f8a2dae3d7f19541432610d114a70808f0926d5aaa7121e4"}, + {file = "cryptography-43.0.1-cp39-abi3-win32.whl", hash = "sha256:a575913fb06e05e6b4b814d7f7468c2c660e8bb16d8d5a1faf9b33ccc569dd47"}, + {file = "cryptography-43.0.1-cp39-abi3-win_amd64.whl", hash = "sha256:d75601ad10b059ec832e78823b348bfa1a59f6b8d545db3a24fd44362a1564cb"}, + {file = "cryptography-43.0.1-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:ea25acb556320250756e53f9e20a4177515f012c9eaea17eb7587a8c4d8ae034"}, + {file = "cryptography-43.0.1-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:c1332724be35d23a854994ff0b66530119500b6053d0bd3363265f7e5e77288d"}, + {file = "cryptography-43.0.1-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:fba1007b3ef89946dbbb515aeeb41e30203b004f0b4b00e5e16078b518563289"}, + {file = "cryptography-43.0.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:5b43d1ea6b378b54a1dc99dd8a2b5be47658fe9a7ce0a58ff0b55f4b43ef2b84"}, + {file = "cryptography-43.0.1-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:88cce104c36870d70c49c7c8fd22885875d950d9ee6ab54df2745f83ba0dc365"}, + {file = "cryptography-43.0.1-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:9d3cdb25fa98afdd3d0892d132b8d7139e2c087da1712041f6b762e4f807cc96"}, + {file = "cryptography-43.0.1-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:e710bf40870f4db63c3d7d929aa9e09e4e7ee219e703f949ec4073b4294f6172"}, + {file = "cryptography-43.0.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:7c05650fe8023c5ed0d46793d4b7d7e6cd9c04e68eabe5b0aeea836e37bdcec2"}, + {file = "cryptography-43.0.1.tar.gz", hash = "sha256:203e92a75716d8cfb491dc47c79e17d0d9207ccffcbcb35f598fbe463ae3444d"}, ] [package.dependencies] @@ -541,7 +617,7 @@ nox = ["nox"] pep8test = ["check-sdist", "click", "mypy", "ruff"] sdist = ["build"] ssh = ["bcrypt (>=3.1.5)"] -test = ["certifi", "pretend", "pytest (>=6.2.0)", "pytest-benchmark", "pytest-cov", "pytest-xdist"] +test = ["certifi", "cryptography-vectors (==43.0.1)", "pretend", "pytest (>=6.2.0)", "pytest-benchmark", "pytest-cov", "pytest-xdist"] test-randomorder = ["pytest-randomly"] [[package]] @@ -619,13 +695,13 @@ files = [ [[package]] name = "exceptiongroup" -version = "1.2.1" +version = "1.2.2" description = "Backport of PEP 654 (exception groups)" optional = false python-versions = ">=3.7" files = [ - {file = "exceptiongroup-1.2.1-py3-none-any.whl", hash = "sha256:5258b9ed329c5bbdd31a309f53cbfb0b155341807f6ff7606a1e801a891b29ad"}, - {file = "exceptiongroup-1.2.1.tar.gz", hash = "sha256:a4785e48b045528f5bfe627b6ad554ff32def154f42372786903b7abcfe1aa16"}, + {file = "exceptiongroup-1.2.2-py3-none-any.whl", hash = "sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b"}, + {file = "exceptiongroup-1.2.2.tar.gz", hash = "sha256:47c2edf7c6738fafb49fd34290706d1a1a2f4d1c6df275526b62cbb4aa5393cc"}, ] [package.extras] @@ -647,18 +723,18 @@ testing = ["hatch", "pre-commit", "pytest", "tox"] [[package]] name = "flake8" -version = "7.0.0" +version = "7.1.1" description = "the modular source code checker: pep8 pyflakes and co" optional = false python-versions = ">=3.8.1" files = [ - {file = "flake8-7.0.0-py2.py3-none-any.whl", hash = "sha256:a6dfbb75e03252917f2473ea9653f7cd799c3064e54d4c8140044c5c065f53c3"}, - {file = "flake8-7.0.0.tar.gz", hash = "sha256:33f96621059e65eec474169085dc92bf26e7b2d47366b70be2f67ab80dc25132"}, + {file = "flake8-7.1.1-py2.py3-none-any.whl", hash = "sha256:597477df7860daa5aa0fdd84bf5208a043ab96b8e96ab708770ae0364dd03213"}, + {file = "flake8-7.1.1.tar.gz", hash = "sha256:049d058491e228e03e67b390f311bbf88fce2dbaa8fa673e7aea87b7198b8d38"}, ] [package.dependencies] mccabe = ">=0.7.0,<0.8.0" -pycodestyle = ">=2.11.0,<2.12.0" +pycodestyle = ">=2.12.0,<2.13.0" pyflakes = ">=3.2.0,<3.3.0" [[package]] @@ -812,15 +888,29 @@ files = [ {file = "frozenlist-1.4.1.tar.gz", hash = "sha256:c037a86e8513059a2613aaba4d817bb90b9d9b6b69aace3ce9c877e8c8ed402b"}, ] +[[package]] +name = "humanfriendly" +version = "10.0" +description = "Human friendly output for text interfaces using Python" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +files = [ + {file = "humanfriendly-10.0-py2.py3-none-any.whl", hash = "sha256:1697e1a8a8f550fd43c2865cd84542fc175a61dcb779b6fee18cf6b6ccba1477"}, + {file = "humanfriendly-10.0.tar.gz", hash = "sha256:6b0b831ce8f15f7300721aa49829fc4e83921a9a301cc7f606be6686a2288ddc"}, +] + +[package.dependencies] +pyreadline3 = {version = "*", markers = "sys_platform == \"win32\" and python_version >= \"3.8\""} + [[package]] name = "idna" -version = "3.7" +version = "3.8" description = "Internationalized Domain Names in Applications (IDNA)" optional = false -python-versions = ">=3.5" +python-versions = ">=3.6" files = [ - {file = "idna-3.7-py3-none-any.whl", hash = "sha256:82fee1fc78add43492d3a1898bfa6d8a904cc97d8427f683ed8e798d07761aa0"}, - {file = "idna-3.7.tar.gz", hash = "sha256:028ff3aadf0609c1fd278d8ea3089299412a7a8b9bd005dd08b9f8285bcb5cfc"}, + {file = "idna-3.8-py3-none-any.whl", hash = "sha256:050b4e5baadcd44d760cedbd2b8e639f2ff89bbc7a5730fcc662954303377aac"}, + {file = "idna-3.8.tar.gz", hash = "sha256:d838c2c0ed6fced7693d5e8ab8e734d5f8fda53a039c0164afb0b82e771e3603"}, ] [[package]] @@ -836,22 +926,22 @@ files = [ [[package]] name = "importlib-metadata" -version = "7.1.0" +version = "8.4.0" description = "Read metadata from Python packages" optional = false python-versions = ">=3.8" files = [ - {file = "importlib_metadata-7.1.0-py3-none-any.whl", hash = "sha256:30962b96c0c223483ed6cc7280e7f0199feb01a0e40cfae4d4450fc6fab1f570"}, - {file = "importlib_metadata-7.1.0.tar.gz", hash = "sha256:b78938b926ee8d5f020fc4772d487045805a55ddbad2ecf21c6d60938dc7fcd2"}, + {file = "importlib_metadata-8.4.0-py3-none-any.whl", hash = "sha256:66f342cc6ac9818fc6ff340576acd24d65ba0b3efabb2b4ac08b598965a4a2f1"}, + {file = "importlib_metadata-8.4.0.tar.gz", hash = "sha256:9a547d3bc3608b025f93d403fdd1aae741c24fbb8314df4b155675742ce303c5"}, ] [package.dependencies] zipp = ">=0.5" [package.extras] -docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] perf = ["ipython"] -testing = ["flufl.flake8", "importlib-resources (>=1.3)", "jaraco.test (>=5.4)", "packaging", "pyfakefs", "pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy", "pytest-perf (>=0.9.2)", "pytest-ruff (>=0.2.1)"] +test = ["flufl.flake8", "importlib-resources (>=1.3)", "jaraco.test (>=5.4)", "packaging", "pyfakefs", "pytest (>=6,!=8.1.*)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy", "pytest-perf (>=0.9.2)", "pytest-ruff (>=0.2.1)"] [[package]] name = "iniconfig" @@ -1054,6 +1144,96 @@ files = [ {file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"}, ] +[[package]] +name = "ogmios" +version = "1.2.1" +description = "Ogmios is a lightweight bridge interface for cardano-node. It offers a WebSockets API that enables local clients to speak Ouroboros' mini-protocols via JSON/RPC. ogmios-python is an Ogmios client written in Python designed for ease of use." +optional = false +python-versions = ">=3.8" +files = [ + {file = "ogmios-1.2.1-py3-none-any.whl", hash = "sha256:a0e1d87f9fd7b224556b30349d8abce2fcff3ce1c9a92e292f9a5c13f1e140ce"}, + {file = "ogmios-1.2.1.tar.gz", hash = "sha256:07d7086ca8ddb4ca38e9c61edda53ff4acc0d156d15ea056eac11cd05390d9ec"}, +] + +[package.dependencies] +cachetools = "*" +cardano-tools = "*" +coloredlogs = "*" +orjson = "*" +pydantic = ">=2.0" +setuptools = ">=69.5.1" +websockets = "*" + +[package.extras] +dev = ["black", "datamodel-code-generator", "flake8-pyproject", "isort", "sphinx", "sphinx-rtd-theme"] +testing = ["coverage[toml] (>=6.5)", "pycardano", "pytest"] + +[[package]] +name = "orjson" +version = "3.10.7" +description = "Fast, correct Python JSON library supporting dataclasses, datetimes, and numpy" +optional = false +python-versions = ">=3.8" +files = [ + {file = "orjson-3.10.7-cp310-cp310-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:74f4544f5a6405b90da8ea724d15ac9c36da4d72a738c64685003337401f5c12"}, + {file = "orjson-3.10.7-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:34a566f22c28222b08875b18b0dfbf8a947e69df21a9ed5c51a6bf91cfb944ac"}, + {file = "orjson-3.10.7-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:bf6ba8ebc8ef5792e2337fb0419f8009729335bb400ece005606336b7fd7bab7"}, + {file = "orjson-3.10.7-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ac7cf6222b29fbda9e3a472b41e6a5538b48f2c8f99261eecd60aafbdb60690c"}, + {file = "orjson-3.10.7-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:de817e2f5fc75a9e7dd350c4b0f54617b280e26d1631811a43e7e968fa71e3e9"}, + {file = "orjson-3.10.7-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:348bdd16b32556cf8d7257b17cf2bdb7ab7976af4af41ebe79f9796c218f7e91"}, + {file = "orjson-3.10.7-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:479fd0844ddc3ca77e0fd99644c7fe2de8e8be1efcd57705b5c92e5186e8a250"}, + {file = "orjson-3.10.7-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:fdf5197a21dd660cf19dfd2a3ce79574588f8f5e2dbf21bda9ee2d2b46924d84"}, + {file = "orjson-3.10.7-cp310-none-win32.whl", hash = "sha256:d374d36726746c81a49f3ff8daa2898dccab6596864ebe43d50733275c629175"}, + {file = "orjson-3.10.7-cp310-none-win_amd64.whl", hash = "sha256:cb61938aec8b0ffb6eef484d480188a1777e67b05d58e41b435c74b9d84e0b9c"}, + {file = "orjson-3.10.7-cp311-cp311-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:7db8539039698ddfb9a524b4dd19508256107568cdad24f3682d5773e60504a2"}, + {file = "orjson-3.10.7-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:480f455222cb7a1dea35c57a67578848537d2602b46c464472c995297117fa09"}, + {file = "orjson-3.10.7-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8a9c9b168b3a19e37fe2778c0003359f07822c90fdff8f98d9d2a91b3144d8e0"}, + {file = "orjson-3.10.7-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8de062de550f63185e4c1c54151bdddfc5625e37daf0aa1e75d2a1293e3b7d9a"}, + {file = "orjson-3.10.7-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6b0dd04483499d1de9c8f6203f8975caf17a6000b9c0c54630cef02e44ee624e"}, + {file = "orjson-3.10.7-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b58d3795dafa334fc8fd46f7c5dc013e6ad06fd5b9a4cc98cb1456e7d3558bd6"}, + {file = "orjson-3.10.7-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:33cfb96c24034a878d83d1a9415799a73dc77480e6c40417e5dda0710d559ee6"}, + {file = "orjson-3.10.7-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:e724cebe1fadc2b23c6f7415bad5ee6239e00a69f30ee423f319c6af70e2a5c0"}, + {file = "orjson-3.10.7-cp311-none-win32.whl", hash = "sha256:82763b46053727a7168d29c772ed5c870fdae2f61aa8a25994c7984a19b1021f"}, + {file = "orjson-3.10.7-cp311-none-win_amd64.whl", hash = "sha256:eb8d384a24778abf29afb8e41d68fdd9a156cf6e5390c04cc07bbc24b89e98b5"}, + {file = "orjson-3.10.7-cp312-cp312-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:44a96f2d4c3af51bfac6bc4ef7b182aa33f2f054fd7f34cc0ee9a320d051d41f"}, + {file = "orjson-3.10.7-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:76ac14cd57df0572453543f8f2575e2d01ae9e790c21f57627803f5e79b0d3c3"}, + {file = "orjson-3.10.7-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:bdbb61dcc365dd9be94e8f7df91975edc9364d6a78c8f7adb69c1cdff318ec93"}, + {file = "orjson-3.10.7-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b48b3db6bb6e0a08fa8c83b47bc169623f801e5cc4f24442ab2b6617da3b5313"}, + {file = "orjson-3.10.7-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:23820a1563a1d386414fef15c249040042b8e5d07b40ab3fe3efbfbbcbcb8864"}, + {file = "orjson-3.10.7-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a0c6a008e91d10a2564edbb6ee5069a9e66df3fbe11c9a005cb411f441fd2c09"}, + {file = "orjson-3.10.7-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:d352ee8ac1926d6193f602cbe36b1643bbd1bbcb25e3c1a657a4390f3000c9a5"}, + {file = "orjson-3.10.7-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:d2d9f990623f15c0ae7ac608103c33dfe1486d2ed974ac3f40b693bad1a22a7b"}, + {file = "orjson-3.10.7-cp312-none-win32.whl", hash = "sha256:7c4c17f8157bd520cdb7195f75ddbd31671997cbe10aee559c2d613592e7d7eb"}, + {file = "orjson-3.10.7-cp312-none-win_amd64.whl", hash = "sha256:1d9c0e733e02ada3ed6098a10a8ee0052dd55774de3d9110d29868d24b17faa1"}, + {file = "orjson-3.10.7-cp313-cp313-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:77d325ed866876c0fa6492598ec01fe30e803272a6e8b10e992288b009cbe149"}, + {file = "orjson-3.10.7-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9ea2c232deedcb605e853ae1db2cc94f7390ac776743b699b50b071b02bea6fe"}, + {file = "orjson-3.10.7-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:3dcfbede6737fdbef3ce9c37af3fb6142e8e1ebc10336daa05872bfb1d87839c"}, + {file = "orjson-3.10.7-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:11748c135f281203f4ee695b7f80bb1358a82a63905f9f0b794769483ea854ad"}, + {file = "orjson-3.10.7-cp313-none-win32.whl", hash = "sha256:a7e19150d215c7a13f39eb787d84db274298d3f83d85463e61d277bbd7f401d2"}, + {file = "orjson-3.10.7-cp313-none-win_amd64.whl", hash = "sha256:eef44224729e9525d5261cc8d28d6b11cafc90e6bd0be2157bde69a52ec83024"}, + {file = "orjson-3.10.7-cp38-cp38-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:6ea2b2258eff652c82652d5e0f02bd5e0463a6a52abb78e49ac288827aaa1469"}, + {file = "orjson-3.10.7-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:430ee4d85841e1483d487e7b81401785a5dfd69db5de01314538f31f8fbf7ee1"}, + {file = "orjson-3.10.7-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:4b6146e439af4c2472c56f8540d799a67a81226e11992008cb47e1267a9b3225"}, + {file = "orjson-3.10.7-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:084e537806b458911137f76097e53ce7bf5806dda33ddf6aaa66a028f8d43a23"}, + {file = "orjson-3.10.7-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4829cf2195838e3f93b70fd3b4292156fc5e097aac3739859ac0dcc722b27ac0"}, + {file = "orjson-3.10.7-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1193b2416cbad1a769f868b1749535d5da47626ac29445803dae7cc64b3f5c98"}, + {file = "orjson-3.10.7-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:4e6c3da13e5a57e4b3dca2de059f243ebec705857522f188f0180ae88badd354"}, + {file = "orjson-3.10.7-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:c31008598424dfbe52ce8c5b47e0752dca918a4fdc4a2a32004efd9fab41d866"}, + {file = "orjson-3.10.7-cp38-none-win32.whl", hash = "sha256:7122a99831f9e7fe977dc45784d3b2edc821c172d545e6420c375e5a935f5a1c"}, + {file = "orjson-3.10.7-cp38-none-win_amd64.whl", hash = "sha256:a763bc0e58504cc803739e7df040685816145a6f3c8a589787084b54ebc9f16e"}, + {file = "orjson-3.10.7-cp39-cp39-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:e76be12658a6fa376fcd331b1ea4e58f5a06fd0220653450f0d415b8fd0fbe20"}, + {file = "orjson-3.10.7-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ed350d6978d28b92939bfeb1a0570c523f6170efc3f0a0ef1f1df287cd4f4960"}, + {file = "orjson-3.10.7-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:144888c76f8520e39bfa121b31fd637e18d4cc2f115727865fdf9fa325b10412"}, + {file = "orjson-3.10.7-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:09b2d92fd95ad2402188cf51573acde57eb269eddabaa60f69ea0d733e789fe9"}, + {file = "orjson-3.10.7-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5b24a579123fa884f3a3caadaed7b75eb5715ee2b17ab5c66ac97d29b18fe57f"}, + {file = "orjson-3.10.7-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e72591bcfe7512353bd609875ab38050efe3d55e18934e2f18950c108334b4ff"}, + {file = "orjson-3.10.7-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:f4db56635b58cd1a200b0a23744ff44206ee6aa428185e2b6c4a65b3197abdcd"}, + {file = "orjson-3.10.7-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:0fa5886854673222618638c6df7718ea7fe2f3f2384c452c9ccedc70b4a510a5"}, + {file = "orjson-3.10.7-cp39-none-win32.whl", hash = "sha256:8272527d08450ab16eb405f47e0f4ef0e5ff5981c3d82afe0efd25dcbef2bcd2"}, + {file = "orjson-3.10.7-cp39-none-win_amd64.whl", hash = "sha256:974683d4618c0c7dbf4f69c95a979734bf183d0658611760017f6e70a145af58"}, + {file = "orjson-3.10.7.tar.gz", hash = "sha256:75ef0640403f945f3a1f9f6400686560dbfb0fb5b16589ad62cd477043c4eee3"}, +] + [[package]] name = "oscrypto" version = "1.3.0" @@ -1070,13 +1250,13 @@ asn1crypto = ">=1.5.1" [[package]] name = "packaging" -version = "24.0" +version = "24.1" description = "Core utilities for Python packages" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "packaging-24.0-py3-none-any.whl", hash = "sha256:2ddfb553fdf02fb784c234c7ba6ccc288296ceabec964ad2eae3777778130bc5"}, - {file = "packaging-24.0.tar.gz", hash = "sha256:eb82c5e3e56209074766e6885bb04b8c38a0c015d0a30036ebe7ece34c9989e9"}, + {file = "packaging-24.1-py3-none-any.whl", hash = "sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124"}, + {file = "packaging-24.1.tar.gz", hash = "sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002"}, ] [[package]] @@ -1090,21 +1270,35 @@ files = [ {file = "pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712"}, ] +[[package]] +name = "pexpect" +version = "4.9.0" +description = "Pexpect allows easy control of interactive console applications." +optional = false +python-versions = "*" +files = [ + {file = "pexpect-4.9.0-py2.py3-none-any.whl", hash = "sha256:7236d1e080e4936be2dc3e326cec0af72acf9212a7e1d060210e70a47e253523"}, + {file = "pexpect-4.9.0.tar.gz", hash = "sha256:ee7d41123f3c9911050ea2c2dac107568dc43b2d3b0c7557a33212c398ead30f"}, +] + +[package.dependencies] +ptyprocess = ">=0.5" + [[package]] name = "platformdirs" -version = "4.2.2" +version = "4.3.2" description = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`." optional = false python-versions = ">=3.8" files = [ - {file = "platformdirs-4.2.2-py3-none-any.whl", hash = "sha256:2d7a1657e36a80ea911db832a8a6ece5ee53d8de21edd5cc5879af6530b1bfee"}, - {file = "platformdirs-4.2.2.tar.gz", hash = "sha256:38b7b51f512eed9e84a22788b4bce1de17c0adb134d6becb09836e37d8654cd3"}, + {file = "platformdirs-4.3.2-py3-none-any.whl", hash = "sha256:eb1c8582560b34ed4ba105009a4badf7f6f85768b30126f351328507b2beb617"}, + {file = "platformdirs-4.3.2.tar.gz", hash = "sha256:9e5e27a08aa095dd127b9f2e764d74254f482fef22b0970773bfba79d091ab8c"}, ] [package.extras] -docs = ["furo (>=2023.9.10)", "proselint (>=0.13)", "sphinx (>=7.2.6)", "sphinx-autodoc-typehints (>=1.25.2)"] -test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.4.3)", "pytest-cov (>=4.1)", "pytest-mock (>=3.12)"] -type = ["mypy (>=1.8)"] +docs = ["furo (>=2024.8.6)", "proselint (>=0.14)", "sphinx (>=8.0.2)", "sphinx-autodoc-typehints (>=2.4)"] +test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=8.3.2)", "pytest-cov (>=5)", "pytest-mock (>=3.14)"] +type = ["mypy (>=1.11.2)"] [[package]] name = "pluggy" @@ -1132,6 +1326,17 @@ files = [ {file = "pprintpp-0.4.0.tar.gz", hash = "sha256:ea826108e2c7f49dc6d66c752973c3fc9749142a798d6b254e1e301cfdbc6403"}, ] +[[package]] +name = "ptyprocess" +version = "0.7.0" +description = "Run a subprocess in a pseudo terminal" +optional = false +python-versions = "*" +files = [ + {file = "ptyprocess-0.7.0-py2.py3-none-any.whl", hash = "sha256:4b41f3967fce3af57cc7e94b888626c18bf37a083e3651ca8feeb66d492fef35"}, + {file = "ptyprocess-0.7.0.tar.gz", hash = "sha256:5c5d0a3b48ceee0b48485e0c26037c0acd7d29765ca3fbb5cb3831d347423220"}, +] + [[package]] name = "py" version = "1.11.0" @@ -1145,13 +1350,13 @@ files = [ [[package]] name = "pycodestyle" -version = "2.11.1" +version = "2.12.1" description = "Python style guide checker" optional = false python-versions = ">=3.8" files = [ - {file = "pycodestyle-2.11.1-py2.py3-none-any.whl", hash = "sha256:44fe31000b2d866f2e41841b18528a505fbd7fef9017b04eff4e2648a0fadc67"}, - {file = "pycodestyle-2.11.1.tar.gz", hash = "sha256:41ba0e7afc9752dfb53ced5489e89f8186be00e599e712660695b7a75ff2663f"}, + {file = "pycodestyle-2.12.1-py2.py3-none-any.whl", hash = "sha256:46f0fb92069a7c28ab7bb558f05bfc0110dac69a0cd23c61ea0040283a9d78b3"}, + {file = "pycodestyle-2.12.1.tar.gz", hash = "sha256:6838eae08bbce4f6accd5d5572075c63626a15ee3e6f842df996bf62f6d73521"}, ] [[package]] @@ -1165,6 +1370,130 @@ files = [ {file = "pycparser-2.22.tar.gz", hash = "sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6"}, ] +[[package]] +name = "pydantic" +version = "2.9.0" +description = "Data validation using Python type hints" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pydantic-2.9.0-py3-none-any.whl", hash = "sha256:f66a7073abd93214a20c5f7b32d56843137a7a2e70d02111f3be287035c45370"}, + {file = "pydantic-2.9.0.tar.gz", hash = "sha256:c7a8a9fdf7d100afa49647eae340e2d23efa382466a8d177efcd1381e9be5598"}, +] + +[package.dependencies] +annotated-types = ">=0.4.0" +pydantic-core = "2.23.2" +typing-extensions = [ + {version = ">=4.12.2", markers = "python_version >= \"3.13\""}, + {version = ">=4.6.1", markers = "python_version < \"3.13\""}, +] +tzdata = {version = "*", markers = "python_version >= \"3.9\""} + +[package.extras] +email = ["email-validator (>=2.0.0)"] + +[[package]] +name = "pydantic-core" +version = "2.23.2" +description = "Core functionality for Pydantic validation and serialization" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pydantic_core-2.23.2-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:7d0324a35ab436c9d768753cbc3c47a865a2cbc0757066cb864747baa61f6ece"}, + {file = "pydantic_core-2.23.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:276ae78153a94b664e700ac362587c73b84399bd1145e135287513442e7dfbc7"}, + {file = "pydantic_core-2.23.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:964c7aa318da542cdcc60d4a648377ffe1a2ef0eb1e996026c7f74507b720a78"}, + {file = "pydantic_core-2.23.2-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:1cf842265a3a820ebc6388b963ead065f5ce8f2068ac4e1c713ef77a67b71f7c"}, + {file = "pydantic_core-2.23.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ae90b9e50fe1bd115b24785e962b51130340408156d34d67b5f8f3fa6540938e"}, + {file = "pydantic_core-2.23.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8ae65fdfb8a841556b52935dfd4c3f79132dc5253b12c0061b96415208f4d622"}, + {file = "pydantic_core-2.23.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5c8aa40f6ca803f95b1c1c5aeaee6237b9e879e4dfb46ad713229a63651a95fb"}, + {file = "pydantic_core-2.23.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c53100c8ee5a1e102766abde2158077d8c374bee0639201f11d3032e3555dfbc"}, + {file = "pydantic_core-2.23.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:d6b9dd6aa03c812017411734e496c44fef29b43dba1e3dd1fa7361bbacfc1354"}, + {file = "pydantic_core-2.23.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:b18cf68255a476b927910c6873d9ed00da692bb293c5b10b282bd48a0afe3ae2"}, + {file = "pydantic_core-2.23.2-cp310-none-win32.whl", hash = "sha256:e460475719721d59cd54a350c1f71c797c763212c836bf48585478c5514d2854"}, + {file = "pydantic_core-2.23.2-cp310-none-win_amd64.whl", hash = "sha256:5f3cf3721eaf8741cffaf092487f1ca80831202ce91672776b02b875580e174a"}, + {file = "pydantic_core-2.23.2-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:7ce8e26b86a91e305858e018afc7a6e932f17428b1eaa60154bd1f7ee888b5f8"}, + {file = "pydantic_core-2.23.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7e9b24cca4037a561422bf5dc52b38d390fb61f7bfff64053ce1b72f6938e6b2"}, + {file = "pydantic_core-2.23.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:753294d42fb072aa1775bfe1a2ba1012427376718fa4c72de52005a3d2a22178"}, + {file = "pydantic_core-2.23.2-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:257d6a410a0d8aeb50b4283dea39bb79b14303e0fab0f2b9d617701331ed1515"}, + {file = "pydantic_core-2.23.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c8319e0bd6a7b45ad76166cc3d5d6a36c97d0c82a196f478c3ee5346566eebfd"}, + {file = "pydantic_core-2.23.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7a05c0240f6c711eb381ac392de987ee974fa9336071fb697768dfdb151345ce"}, + {file = "pydantic_core-2.23.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8d5b0ff3218858859910295df6953d7bafac3a48d5cd18f4e3ed9999efd2245f"}, + {file = "pydantic_core-2.23.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:96ef39add33ff58cd4c112cbac076726b96b98bb8f1e7f7595288dcfb2f10b57"}, + {file = "pydantic_core-2.23.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:0102e49ac7d2df3379ef8d658d3bc59d3d769b0bdb17da189b75efa861fc07b4"}, + {file = "pydantic_core-2.23.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:a6612c2a844043e4d10a8324c54cdff0042c558eef30bd705770793d70b224aa"}, + {file = "pydantic_core-2.23.2-cp311-none-win32.whl", hash = "sha256:caffda619099cfd4f63d48462f6aadbecee3ad9603b4b88b60cb821c1b258576"}, + {file = "pydantic_core-2.23.2-cp311-none-win_amd64.whl", hash = "sha256:6f80fba4af0cb1d2344869d56430e304a51396b70d46b91a55ed4959993c0589"}, + {file = "pydantic_core-2.23.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:4c83c64d05ffbbe12d4e8498ab72bdb05bcc1026340a4a597dc647a13c1605ec"}, + {file = "pydantic_core-2.23.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6294907eaaccf71c076abdd1c7954e272efa39bb043161b4b8aa1cd76a16ce43"}, + {file = "pydantic_core-2.23.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4a801c5e1e13272e0909c520708122496647d1279d252c9e6e07dac216accc41"}, + {file = "pydantic_core-2.23.2-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:cc0c316fba3ce72ac3ab7902a888b9dc4979162d320823679da270c2d9ad0cad"}, + {file = "pydantic_core-2.23.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6b06c5d4e8701ac2ba99a2ef835e4e1b187d41095a9c619c5b185c9068ed2a49"}, + {file = "pydantic_core-2.23.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:82764c0bd697159fe9947ad59b6db6d7329e88505c8f98990eb07e84cc0a5d81"}, + {file = "pydantic_core-2.23.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2b1a195efd347ede8bcf723e932300292eb13a9d2a3c1f84eb8f37cbbc905b7f"}, + {file = "pydantic_core-2.23.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b7efb12e5071ad8d5b547487bdad489fbd4a5a35a0fc36a1941517a6ad7f23e0"}, + {file = "pydantic_core-2.23.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:5dd0ec5f514ed40e49bf961d49cf1bc2c72e9b50f29a163b2cc9030c6742aa73"}, + {file = "pydantic_core-2.23.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:820f6ee5c06bc868335e3b6e42d7ef41f50dfb3ea32fbd523ab679d10d8741c0"}, + {file = "pydantic_core-2.23.2-cp312-none-win32.whl", hash = "sha256:3713dc093d5048bfaedbba7a8dbc53e74c44a140d45ede020dc347dda18daf3f"}, + {file = "pydantic_core-2.23.2-cp312-none-win_amd64.whl", hash = "sha256:e1895e949f8849bc2757c0dbac28422a04be031204df46a56ab34bcf98507342"}, + {file = "pydantic_core-2.23.2-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:da43cbe593e3c87d07108d0ebd73771dc414488f1f91ed2e204b0370b94b37ac"}, + {file = "pydantic_core-2.23.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:64d094ea1aa97c6ded4748d40886076a931a8bf6f61b6e43e4a1041769c39dd2"}, + {file = "pydantic_core-2.23.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:084414ffe9a85a52940b49631321d636dadf3576c30259607b75516d131fecd0"}, + {file = "pydantic_core-2.23.2-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:043ef8469f72609c4c3a5e06a07a1f713d53df4d53112c6d49207c0bd3c3bd9b"}, + {file = "pydantic_core-2.23.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3649bd3ae6a8ebea7dc381afb7f3c6db237fc7cebd05c8ac36ca8a4187b03b30"}, + {file = "pydantic_core-2.23.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6db09153d8438425e98cdc9a289c5fade04a5d2128faff8f227c459da21b9703"}, + {file = "pydantic_core-2.23.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5668b3173bb0b2e65020b60d83f5910a7224027232c9f5dc05a71a1deac9f960"}, + {file = "pydantic_core-2.23.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1c7b81beaf7c7ebde978377dc53679c6cba0e946426fc7ade54251dfe24a7604"}, + {file = "pydantic_core-2.23.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:ae579143826c6f05a361d9546446c432a165ecf1c0b720bbfd81152645cb897d"}, + {file = "pydantic_core-2.23.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:19f1352fe4b248cae22a89268720fc74e83f008057a652894f08fa931e77dced"}, + {file = "pydantic_core-2.23.2-cp313-none-win32.whl", hash = "sha256:e1a79ad49f346aa1a2921f31e8dbbab4d64484823e813a002679eaa46cba39e1"}, + {file = "pydantic_core-2.23.2-cp313-none-win_amd64.whl", hash = "sha256:582871902e1902b3c8e9b2c347f32a792a07094110c1bca6c2ea89b90150caac"}, + {file = "pydantic_core-2.23.2-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:743e5811b0c377eb830150d675b0847a74a44d4ad5ab8845923d5b3a756d8100"}, + {file = "pydantic_core-2.23.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:6650a7bbe17a2717167e3e23c186849bae5cef35d38949549f1c116031b2b3aa"}, + {file = "pydantic_core-2.23.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:56e6a12ec8d7679f41b3750ffa426d22b44ef97be226a9bab00a03365f217b2b"}, + {file = "pydantic_core-2.23.2-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:810ca06cca91de9107718dc83d9ac4d2e86efd6c02cba49a190abcaf33fb0472"}, + {file = "pydantic_core-2.23.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:785e7f517ebb9890813d31cb5d328fa5eda825bb205065cde760b3150e4de1f7"}, + {file = "pydantic_core-2.23.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3ef71ec876fcc4d3bbf2ae81961959e8d62f8d74a83d116668409c224012e3af"}, + {file = "pydantic_core-2.23.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d50ac34835c6a4a0d456b5db559b82047403c4317b3bc73b3455fefdbdc54b0a"}, + {file = "pydantic_core-2.23.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:16b25a4a120a2bb7dab51b81e3d9f3cde4f9a4456566c403ed29ac81bf49744f"}, + {file = "pydantic_core-2.23.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:41ae8537ad371ec018e3c5da0eb3f3e40ee1011eb9be1da7f965357c4623c501"}, + {file = "pydantic_core-2.23.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:07049ec9306ec64e955b2e7c40c8d77dd78ea89adb97a2013d0b6e055c5ee4c5"}, + {file = "pydantic_core-2.23.2-cp38-none-win32.whl", hash = "sha256:086c5db95157dc84c63ff9d96ebb8856f47ce113c86b61065a066f8efbe80acf"}, + {file = "pydantic_core-2.23.2-cp38-none-win_amd64.whl", hash = "sha256:67b6655311b00581914aba481729971b88bb8bc7996206590700a3ac85e457b8"}, + {file = "pydantic_core-2.23.2-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:358331e21a897151e54d58e08d0219acf98ebb14c567267a87e971f3d2a3be59"}, + {file = "pydantic_core-2.23.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c4d9f15ffe68bcd3898b0ad7233af01b15c57d91cd1667f8d868e0eacbfe3f87"}, + {file = "pydantic_core-2.23.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0123655fedacf035ab10c23450163c2f65a4174f2bb034b188240a6cf06bb123"}, + {file = "pydantic_core-2.23.2-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e6e3ccebdbd6e53474b0bb7ab8b88e83c0cfe91484b25e058e581348ee5a01a5"}, + {file = "pydantic_core-2.23.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fc535cb898ef88333cf317777ecdfe0faac1c2a3187ef7eb061b6f7ecf7e6bae"}, + {file = "pydantic_core-2.23.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:aab9e522efff3993a9e98ab14263d4e20211e62da088298089a03056980a3e69"}, + {file = "pydantic_core-2.23.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:05b366fb8fe3d8683b11ac35fa08947d7b92be78ec64e3277d03bd7f9b7cda79"}, + {file = "pydantic_core-2.23.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:7568f682c06f10f30ef643a1e8eec4afeecdafde5c4af1b574c6df079e96f96c"}, + {file = "pydantic_core-2.23.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:cdd02a08205dc90238669f082747612cb3c82bd2c717adc60f9b9ecadb540f80"}, + {file = "pydantic_core-2.23.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:1a2ab4f410f4b886de53b6bddf5dd6f337915a29dd9f22f20f3099659536b2f6"}, + {file = "pydantic_core-2.23.2-cp39-none-win32.whl", hash = "sha256:0448b81c3dfcde439551bb04a9f41d7627f676b12701865c8a2574bcea034437"}, + {file = "pydantic_core-2.23.2-cp39-none-win_amd64.whl", hash = "sha256:4cebb9794f67266d65e7e4cbe5dcf063e29fc7b81c79dc9475bd476d9534150e"}, + {file = "pydantic_core-2.23.2-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:e758d271ed0286d146cf7c04c539a5169a888dd0b57026be621547e756af55bc"}, + {file = "pydantic_core-2.23.2-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:f477d26183e94eaafc60b983ab25af2a809a1b48ce4debb57b343f671b7a90b6"}, + {file = "pydantic_core-2.23.2-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da3131ef2b940b99106f29dfbc30d9505643f766704e14c5d5e504e6a480c35e"}, + {file = "pydantic_core-2.23.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:329a721253c7e4cbd7aad4a377745fbcc0607f9d72a3cc2102dd40519be75ed2"}, + {file = "pydantic_core-2.23.2-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:7706e15cdbf42f8fab1e6425247dfa98f4a6f8c63746c995d6a2017f78e619ae"}, + {file = "pydantic_core-2.23.2-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:e64ffaf8f6e17ca15eb48344d86a7a741454526f3a3fa56bc493ad9d7ec63936"}, + {file = "pydantic_core-2.23.2-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:dd59638025160056687d598b054b64a79183f8065eae0d3f5ca523cde9943940"}, + {file = "pydantic_core-2.23.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:12625e69b1199e94b0ae1c9a95d000484ce9f0182f9965a26572f054b1537e44"}, + {file = "pydantic_core-2.23.2-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:5d813fd871b3d5c3005157622ee102e8908ad6011ec915a18bd8fde673c4360e"}, + {file = "pydantic_core-2.23.2-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:1eb37f7d6a8001c0f86dc8ff2ee8d08291a536d76e49e78cda8587bb54d8b329"}, + {file = "pydantic_core-2.23.2-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7ce7eaf9a98680b4312b7cebcdd9352531c43db00fca586115845df388f3c465"}, + {file = "pydantic_core-2.23.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f087879f1ffde024dd2788a30d55acd67959dcf6c431e9d3682d1c491a0eb474"}, + {file = "pydantic_core-2.23.2-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:6ce883906810b4c3bd90e0ada1f9e808d9ecf1c5f0b60c6b8831d6100bcc7dd6"}, + {file = "pydantic_core-2.23.2-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:a8031074a397a5925d06b590121f8339d34a5a74cfe6970f8a1124eb8b83f4ac"}, + {file = "pydantic_core-2.23.2-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:23af245b8f2f4ee9e2c99cb3f93d0e22fb5c16df3f2f643f5a8da5caff12a653"}, + {file = "pydantic_core-2.23.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:c57e493a0faea1e4c38f860d6862ba6832723396c884fbf938ff5e9b224200e2"}, + {file = "pydantic_core-2.23.2.tar.gz", hash = "sha256:95d6bf449a1ac81de562d65d180af5d8c19672793c81877a2eda8fde5d08f2fd"}, +] + +[package.dependencies] +typing-extensions = ">=4.6.0,<4.7.0 || >4.7.0" + [[package]] name = "pyflakes" version = "3.2.0" @@ -1216,15 +1545,26 @@ cffi = ">=1.4.1" docs = ["sphinx (>=1.6.5)", "sphinx-rtd-theme"] tests = ["hypothesis (>=3.27.0)", "pytest (>=3.2.1,!=3.3.0)"] +[[package]] +name = "pyreadline3" +version = "3.4.1" +description = "A python implementation of GNU readline." +optional = false +python-versions = "*" +files = [ + {file = "pyreadline3-3.4.1-py3-none-any.whl", hash = "sha256:b0efb6516fd4fb07b45949053826a62fa4cb353db5be2bbb4a7aa1fdd1e345fb"}, + {file = "pyreadline3-3.4.1.tar.gz", hash = "sha256:6f3d1f7b8a31ba32b73917cefc1f28cc660562f39aea8646d30bd6eff21f7bae"}, +] + [[package]] name = "pytest" -version = "8.2.1" +version = "8.3.2" description = "pytest: simple powerful testing with Python" optional = false python-versions = ">=3.8" files = [ - {file = "pytest-8.2.1-py3-none-any.whl", hash = "sha256:faccc5d332b8c3719f40283d0d44aa5cf101cec36f88cde9ed8f2bc0538612b1"}, - {file = "pytest-8.2.1.tar.gz", hash = "sha256:5046e5b46d8e4cac199c373041f26be56fdb81eb4e67dc11d4e10811fc3408fd"}, + {file = "pytest-8.3.2-py3-none-any.whl", hash = "sha256:4ba08f9ae7dcf84ded419494d229b48d0903ea6407b030eaec46df5e6a73bba5"}, + {file = "pytest-8.3.2.tar.gz", hash = "sha256:c132345d12ce551242c87269de812483f5bcc87cdbb4722e48487ba194f9fdce"}, ] [package.dependencies] @@ -1232,7 +1572,7 @@ colorama = {version = "*", markers = "sys_platform == \"win32\""} exceptiongroup = {version = ">=1.0.0rc8", markers = "python_version < \"3.11\""} iniconfig = "*" packaging = "*" -pluggy = ">=1.5,<2.0" +pluggy = ">=1.5,<2" tomli = {version = ">=1", markers = "python_version < \"3.11\""} [package.extras] @@ -1605,24 +1945,35 @@ urllib3 = ">=2" [[package]] name = "typing-extensions" -version = "4.12.0" +version = "4.12.2" description = "Backported and Experimental Type Hints for Python 3.8+" optional = false python-versions = ">=3.8" files = [ - {file = "typing_extensions-4.12.0-py3-none-any.whl", hash = "sha256:b349c66bea9016ac22978d800cfff206d5f9816951f12a7d0ec5578b0a819594"}, - {file = "typing_extensions-4.12.0.tar.gz", hash = "sha256:8cbcdc8606ebcb0d95453ad7dc5065e6237b6aa230a31e81d0f440c30fed5fd8"}, + {file = "typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d"}, + {file = "typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"}, +] + +[[package]] +name = "tzdata" +version = "2024.1" +description = "Provider of IANA time zone data" +optional = false +python-versions = ">=2" +files = [ + {file = "tzdata-2024.1-py2.py3-none-any.whl", hash = "sha256:9068bc196136463f5245e51efda838afa15aaeca9903f49050dfa2679db4d252"}, + {file = "tzdata-2024.1.tar.gz", hash = "sha256:2674120f8d891909751c38abcdfd386ac0a5a1127954fbc332af6b5ceae07efd"}, ] [[package]] name = "urllib3" -version = "2.2.1" +version = "2.2.2" description = "HTTP library with thread-safe connection pooling, file post, and more." optional = false python-versions = ">=3.8" files = [ - {file = "urllib3-2.2.1-py3-none-any.whl", hash = "sha256:450b20ec296a467077128bff42b73080516e71b56ff59a60a02bef2232c4fa9d"}, - {file = "urllib3-2.2.1.tar.gz", hash = "sha256:d0570876c61ab9e520d776c38acbbb5b05a776d3f9ff98a5c8fd5162a444cf19"}, + {file = "urllib3-2.2.2-py3-none-any.whl", hash = "sha256:a448b2f64d686155468037e1ace9f2d2199776e17f0a46610480d311f73e3472"}, + {file = "urllib3-2.2.2.tar.gz", hash = "sha256:dd505485549a7a552833da5e6063639d0d177c04f23bc3864e41e5dc5f612168"}, ] [package.extras] @@ -1647,15 +1998,110 @@ docs = ["Sphinx (>=6.0)", "myst-parser (>=2.0.0)", "sphinx-rtd-theme (>=1.1.0)"] optional = ["python-socks", "wsaccel"] test = ["websockets"] +[[package]] +name = "websockets" +version = "13.0.1" +description = "An implementation of the WebSocket Protocol (RFC 6455 & 7692)" +optional = false +python-versions = ">=3.8" +files = [ + {file = "websockets-13.0.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:1841c9082a3ba4a05ea824cf6d99570a6a2d8849ef0db16e9c826acb28089e8f"}, + {file = "websockets-13.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c5870b4a11b77e4caa3937142b650fbbc0914a3e07a0cf3131f35c0587489c1c"}, + {file = "websockets-13.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f1d3d1f2eb79fe7b0fb02e599b2bf76a7619c79300fc55f0b5e2d382881d4f7f"}, + {file = "websockets-13.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:15c7d62ee071fa94a2fc52c2b472fed4af258d43f9030479d9c4a2de885fd543"}, + {file = "websockets-13.0.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6724b554b70d6195ba19650fef5759ef11346f946c07dbbe390e039bcaa7cc3d"}, + {file = "websockets-13.0.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:56a952fa2ae57a42ba7951e6b2605e08a24801a4931b5644dfc68939e041bc7f"}, + {file = "websockets-13.0.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:17118647c0ea14796364299e942c330d72acc4b248e07e639d34b75067b3cdd8"}, + {file = "websockets-13.0.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:64a11aae1de4c178fa653b07d90f2fb1a2ed31919a5ea2361a38760192e1858b"}, + {file = "websockets-13.0.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:0617fd0b1d14309c7eab6ba5deae8a7179959861846cbc5cb528a7531c249448"}, + {file = "websockets-13.0.1-cp310-cp310-win32.whl", hash = "sha256:11f9976ecbc530248cf162e359a92f37b7b282de88d1d194f2167b5e7ad80ce3"}, + {file = "websockets-13.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:c3c493d0e5141ec055a7d6809a28ac2b88d5b878bb22df8c621ebe79a61123d0"}, + {file = "websockets-13.0.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:699ba9dd6a926f82a277063603fc8d586b89f4cb128efc353b749b641fcddda7"}, + {file = "websockets-13.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cf2fae6d85e5dc384bf846f8243ddaa9197f3a1a70044f59399af001fd1f51d4"}, + {file = "websockets-13.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:52aed6ef21a0f1a2a5e310fb5c42d7555e9c5855476bbd7173c3aa3d8a0302f2"}, + {file = "websockets-13.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8eb2b9a318542153674c6e377eb8cb9ca0fc011c04475110d3477862f15d29f0"}, + {file = "websockets-13.0.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5df891c86fe68b2c38da55b7aea7095beca105933c697d719f3f45f4220a5e0e"}, + {file = "websockets-13.0.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fac2d146ff30d9dd2fcf917e5d147db037a5c573f0446c564f16f1f94cf87462"}, + {file = "websockets-13.0.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:b8ac5b46fd798bbbf2ac6620e0437c36a202b08e1f827832c4bf050da081b501"}, + {file = "websockets-13.0.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:46af561eba6f9b0848b2c9d2427086cabadf14e0abdd9fde9d72d447df268418"}, + {file = "websockets-13.0.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b5a06d7f60bc2fc378a333978470dfc4e1415ee52f5f0fce4f7853eb10c1e9df"}, + {file = "websockets-13.0.1-cp311-cp311-win32.whl", hash = "sha256:556e70e4f69be1082e6ef26dcb70efcd08d1850f5d6c5f4f2bcb4e397e68f01f"}, + {file = "websockets-13.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:67494e95d6565bf395476e9d040037ff69c8b3fa356a886b21d8422ad86ae075"}, + {file = "websockets-13.0.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:f9c9e258e3d5efe199ec23903f5da0eeaad58cf6fccb3547b74fd4750e5ac47a"}, + {file = "websockets-13.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:6b41a1b3b561f1cba8321fb32987552a024a8f67f0d05f06fcf29f0090a1b956"}, + {file = "websockets-13.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f73e676a46b0fe9426612ce8caeca54c9073191a77c3e9d5c94697aef99296af"}, + {file = "websockets-13.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f613289f4a94142f914aafad6c6c87903de78eae1e140fa769a7385fb232fdf"}, + {file = "websockets-13.0.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0f52504023b1480d458adf496dc1c9e9811df4ba4752f0bc1f89ae92f4f07d0c"}, + {file = "websockets-13.0.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:139add0f98206cb74109faf3611b7783ceafc928529c62b389917a037d4cfdf4"}, + {file = "websockets-13.0.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:47236c13be337ef36546004ce8c5580f4b1150d9538b27bf8a5ad8edf23ccfab"}, + {file = "websockets-13.0.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:c44ca9ade59b2e376612df34e837013e2b273e6c92d7ed6636d0556b6f4db93d"}, + {file = "websockets-13.0.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:9bbc525f4be3e51b89b2a700f5746c2a6907d2e2ef4513a8daafc98198b92237"}, + {file = "websockets-13.0.1-cp312-cp312-win32.whl", hash = "sha256:3624fd8664f2577cf8de996db3250662e259bfbc870dd8ebdcf5d7c6ac0b5185"}, + {file = "websockets-13.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:0513c727fb8adffa6d9bf4a4463b2bade0186cbd8c3604ae5540fae18a90cb99"}, + {file = "websockets-13.0.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:1ee4cc030a4bdab482a37462dbf3ffb7e09334d01dd37d1063be1136a0d825fa"}, + {file = "websockets-13.0.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:dbb0b697cc0655719522406c059eae233abaa3243821cfdfab1215d02ac10231"}, + {file = "websockets-13.0.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:acbebec8cb3d4df6e2488fbf34702cbc37fc39ac7abf9449392cefb3305562e9"}, + {file = "websockets-13.0.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:63848cdb6fcc0bf09d4a155464c46c64ffdb5807ede4fb251da2c2692559ce75"}, + {file = "websockets-13.0.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:872afa52a9f4c414d6955c365b6588bc4401272c629ff8321a55f44e3f62b553"}, + {file = "websockets-13.0.1-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:05e70fec7c54aad4d71eae8e8cab50525e899791fc389ec6f77b95312e4e9920"}, + {file = "websockets-13.0.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:e82db3756ccb66266504f5a3de05ac6b32f287faacff72462612120074103329"}, + {file = "websockets-13.0.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:4e85f46ce287f5c52438bb3703d86162263afccf034a5ef13dbe4318e98d86e7"}, + {file = "websockets-13.0.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:f3fea72e4e6edb983908f0db373ae0732b275628901d909c382aae3b592589f2"}, + {file = "websockets-13.0.1-cp313-cp313-win32.whl", hash = "sha256:254ecf35572fca01a9f789a1d0f543898e222f7b69ecd7d5381d8d8047627bdb"}, + {file = "websockets-13.0.1-cp313-cp313-win_amd64.whl", hash = "sha256:ca48914cdd9f2ccd94deab5bcb5ac98025a5ddce98881e5cce762854a5de330b"}, + {file = "websockets-13.0.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:b74593e9acf18ea5469c3edaa6b27fa7ecf97b30e9dabd5a94c4c940637ab96e"}, + {file = "websockets-13.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:132511bfd42e77d152c919147078460c88a795af16b50e42a0bd14f0ad71ddd2"}, + {file = "websockets-13.0.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:165bedf13556f985a2aa064309baa01462aa79bf6112fbd068ae38993a0e1f1b"}, + {file = "websockets-13.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e801ca2f448850685417d723ec70298feff3ce4ff687c6f20922c7474b4746ae"}, + {file = "websockets-13.0.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:30d3a1f041360f029765d8704eae606781e673e8918e6b2c792e0775de51352f"}, + {file = "websockets-13.0.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:67648f5e50231b5a7f6d83b32f9c525e319f0ddc841be0de64f24928cd75a603"}, + {file = "websockets-13.0.1-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:4f0426d51c8f0926a4879390f53c7f5a855e42d68df95fff6032c82c888b5f36"}, + {file = "websockets-13.0.1-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:ef48e4137e8799998a343706531e656fdec6797b80efd029117edacb74b0a10a"}, + {file = "websockets-13.0.1-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:249aab278810bee585cd0d4de2f08cfd67eed4fc75bde623be163798ed4db2eb"}, + {file = "websockets-13.0.1-cp38-cp38-win32.whl", hash = "sha256:06c0a667e466fcb56a0886d924b5f29a7f0886199102f0a0e1c60a02a3751cb4"}, + {file = "websockets-13.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:1f3cf6d6ec1142412d4535adabc6bd72a63f5f148c43fe559f06298bc21953c9"}, + {file = "websockets-13.0.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:1fa082ea38d5de51dd409434edc27c0dcbd5fed2b09b9be982deb6f0508d25bc"}, + {file = "websockets-13.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:4a365bcb7be554e6e1f9f3ed64016e67e2fa03d7b027a33e436aecf194febb63"}, + {file = "websockets-13.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:10a0dc7242215d794fb1918f69c6bb235f1f627aaf19e77f05336d147fce7c37"}, + {file = "websockets-13.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:59197afd478545b1f73367620407b0083303569c5f2d043afe5363676f2697c9"}, + {file = "websockets-13.0.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7d20516990d8ad557b5abeb48127b8b779b0b7e6771a265fa3e91767596d7d97"}, + {file = "websockets-13.0.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a1a2e272d067030048e1fe41aa1ec8cfbbaabce733b3d634304fa2b19e5c897f"}, + {file = "websockets-13.0.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:ad327ac80ba7ee61da85383ca8822ff808ab5ada0e4a030d66703cc025b021c4"}, + {file = "websockets-13.0.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:518f90e6dd089d34eaade01101fd8a990921c3ba18ebbe9b0165b46ebff947f0"}, + {file = "websockets-13.0.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:68264802399aed6fe9652e89761031acc734fc4c653137a5911c2bfa995d6d6d"}, + {file = "websockets-13.0.1-cp39-cp39-win32.whl", hash = "sha256:a5dc0c42ded1557cc7c3f0240b24129aefbad88af4f09346164349391dea8e58"}, + {file = "websockets-13.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:b448a0690ef43db5ef31b3a0d9aea79043882b4632cfc3eaab20105edecf6097"}, + {file = "websockets-13.0.1-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:faef9ec6354fe4f9a2c0bbb52fb1ff852effc897e2a4501e25eb3a47cb0a4f89"}, + {file = "websockets-13.0.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:03d3f9ba172e0a53e37fa4e636b86cc60c3ab2cfee4935e66ed1d7acaa4625ad"}, + {file = "websockets-13.0.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d450f5a7a35662a9b91a64aefa852f0c0308ee256122f5218a42f1d13577d71e"}, + {file = "websockets-13.0.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3f55b36d17ac50aa8a171b771e15fbe1561217510c8768af3d546f56c7576cdc"}, + {file = "websockets-13.0.1-pp310-pypy310_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:14b9c006cac63772b31abbcd3e3abb6228233eec966bf062e89e7fa7ae0b7333"}, + {file = "websockets-13.0.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:b79915a1179a91f6c5f04ece1e592e2e8a6bd245a0e45d12fd56b2b59e559a32"}, + {file = "websockets-13.0.1-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:f40de079779acbcdbb6ed4c65af9f018f8b77c5ec4e17a4b737c05c2db554491"}, + {file = "websockets-13.0.1-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:80e4ba642fc87fa532bac07e5ed7e19d56940b6af6a8c61d4429be48718a380f"}, + {file = "websockets-13.0.1-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2a02b0161c43cc9e0232711eff846569fad6ec836a7acab16b3cf97b2344c060"}, + {file = "websockets-13.0.1-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6aa74a45d4cdc028561a7d6ab3272c8b3018e23723100b12e58be9dfa5a24491"}, + {file = "websockets-13.0.1-pp38-pypy38_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:00fd961943b6c10ee6f0b1130753e50ac5dcd906130dcd77b0003c3ab797d026"}, + {file = "websockets-13.0.1-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:d93572720d781331fb10d3da9ca1067817d84ad1e7c31466e9f5e59965618096"}, + {file = "websockets-13.0.1-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:71e6e5a3a3728886caee9ab8752e8113670936a193284be9d6ad2176a137f376"}, + {file = "websockets-13.0.1-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:c4a6343e3b0714e80da0b0893543bf9a5b5fa71b846ae640e56e9abc6fbc4c83"}, + {file = "websockets-13.0.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1a678532018e435396e37422a95e3ab87f75028ac79570ad11f5bf23cd2a7d8c"}, + {file = "websockets-13.0.1-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d6716c087e4aa0b9260c4e579bb82e068f84faddb9bfba9906cb87726fa2e870"}, + {file = "websockets-13.0.1-pp39-pypy39_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e33505534f3f673270dd67f81e73550b11de5b538c56fe04435d63c02c3f26b5"}, + {file = "websockets-13.0.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:acab3539a027a85d568c2573291e864333ec9d912675107d6efceb7e2be5d980"}, + {file = "websockets-13.0.1-py3-none-any.whl", hash = "sha256:b80f0c51681c517604152eb6a572f5a9378f877763231fddb883ba2f968e8817"}, + {file = "websockets-13.0.1.tar.gz", hash = "sha256:4d6ece65099411cfd9a48d13701d7438d9c34f479046b34c50ff60bb8834e43e"}, +] + [[package]] name = "werkzeug" -version = "3.0.3" +version = "3.0.4" description = "The comprehensive WSGI web application library." optional = false python-versions = ">=3.8" files = [ - {file = "werkzeug-3.0.3-py3-none-any.whl", hash = "sha256:fc9645dc43e03e4d630d23143a04a7f947a9a3b5727cd535fdfe155a17cc48c8"}, - {file = "werkzeug-3.0.3.tar.gz", hash = "sha256:097e5bfda9f0aba8da6b8545146def481d06aa7d3266e7448e2cccf67dd8bd18"}, + {file = "werkzeug-3.0.4-py3-none-any.whl", hash = "sha256:02c9eb92b7d6c06f31a782811505d2157837cea66aaede3e217c7c27c039476c"}, + {file = "werkzeug-3.0.4.tar.gz", hash = "sha256:34f2371506b250df4d4f84bfe7b0921e4762525762bbd936614909fe25cd7306"}, ] [package.dependencies] @@ -1666,20 +2112,24 @@ watchdog = ["watchdog (>=2.3)"] [[package]] name = "zipp" -version = "3.19.1" +version = "3.20.1" description = "Backport of pathlib-compatible object wrapper for zip files" optional = false python-versions = ">=3.8" files = [ - {file = "zipp-3.19.1-py3-none-any.whl", hash = "sha256:2828e64edb5386ea6a52e7ba7cdb17bb30a73a858f5eb6eb93d8d36f5ea26091"}, - {file = "zipp-3.19.1.tar.gz", hash = "sha256:35427f6d5594f4acf82d25541438348c26736fa9b3afa2754bcd63cdb99d8e8f"}, + {file = "zipp-3.20.1-py3-none-any.whl", hash = "sha256:9960cd8967c8f85a56f920d5d507274e74f9ff813a0ab8889a5b5be2daf44064"}, + {file = "zipp-3.20.1.tar.gz", hash = "sha256:c22b14cc4763c5a5b04134207736c107db42e9d3ef2d9779d465f5f1bcba572b"}, ] [package.extras] +check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1)"] +cover = ["pytest-cov"] doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] -test = ["big-O", "jaraco.functools", "jaraco.itertools", "jaraco.test", "more-itertools", "pytest (>=6,!=8.1.*)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-ignore-flaky", "pytest-mypy", "pytest-ruff (>=0.2.1)"] +enabler = ["pytest-enabler (>=2.2)"] +test = ["big-O", "importlib-resources", "jaraco.functools", "jaraco.itertools", "jaraco.test", "more-itertools", "pytest (>=6,!=8.1.*)", "pytest-ignore-flaky"] +type = ["pytest-mypy"] [metadata] lock-version = "2.0" python-versions = "^3.8.1" -content-hash = "f31a679539ac947fa6513bb72fa994e992f128bd666dba7fd87d57f2e315fedf" +content-hash = "6d51d31457690660a1333713b89e6247d2f25b91d1b4737b2c8de8c58f7843ec" diff --git a/pycardano/backend/__init__.py b/pycardano/backend/__init__.py index 515b7cde..617d36c1 100644 --- a/pycardano/backend/__init__.py +++ b/pycardano/backend/__init__.py @@ -3,4 +3,5 @@ from .base import * from .blockfrost import * from .cardano_cli import * -from .ogmios import * +from .ogmios_v5 import * +from .ogmios_v6 import * diff --git a/pycardano/backend/base.py b/pycardano/backend/base.py index aec6948a..7e3fb145 100644 --- a/pycardano/backend/base.py +++ b/pycardano/backend/base.py @@ -2,7 +2,7 @@ from dataclasses import dataclass from fractions import Fraction -from typing import Dict, List, Union +from typing import Dict, List, Optional, Union from pycardano.address import Address from pycardano.exception import InvalidArgumentException @@ -109,6 +109,10 @@ class ProtocolParameters: """A dict contains cost models for Plutus. The key will be "PlutusV1", "PlutusV2", etc. The value will be a dict of cost model parameters.""" + maximum_reference_scripts_size: Optional[Dict[str, int]] = None + + min_fee_reference_scripts: Optional[Dict[str, float]] = None + @typechecked class ChainContext: diff --git a/pycardano/backend/blockfrost.py b/pycardano/backend/blockfrost.py index 40c9ccc7..3d5d1afe 100644 --- a/pycardano/backend/blockfrost.py +++ b/pycardano/backend/blockfrost.py @@ -20,7 +20,13 @@ from pycardano.hash import SCRIPT_HASH_SIZE, DatumHash, ScriptHash from pycardano.nativescript import NativeScript from pycardano.network import Network -from pycardano.plutus import ExecutionUnits, PlutusV1Script, PlutusV2Script, script_hash +from pycardano.plutus import ( + ExecutionUnits, + PlutusV1Script, + PlutusV2Script, + PlutusV3Script, + script_hash, +) from pycardano.serialization import RawCBOR from pycardano.transaction import ( Asset, @@ -37,8 +43,8 @@ def _try_fix_script( - scripth: str, script: Union[PlutusV1Script, PlutusV2Script] -) -> Union[PlutusV1Script, PlutusV2Script]: + scripth: str, script: Union[PlutusV1Script, PlutusV2Script, PlutusV3Script] +) -> Union[PlutusV1Script, PlutusV2Script, PlutusV3Script]: if str(script_hash(script)) == scripth: return script else: @@ -165,12 +171,18 @@ def protocol_param(self) -> ProtocolParameters: cost_models={ k: v.to_dict() for k, v in params.cost_models.to_dict().items() }, + maximum_reference_scripts_size={"bytes": 200000}, + min_fee_reference_scripts={ + "base": params.min_fee_ref_script_cost_per_byte, + "range": 200000, + "multiplier": 1, + }, ) return self._protocol_param def _get_script( self, script_hash: str - ) -> Union[PlutusV1Script, PlutusV2Script, NativeScript]: + ) -> Union[PlutusV1Script, PlutusV2Script, PlutusV3Script, NativeScript]: script_type = self.api.script(script_hash).type if script_type == "plutusV1": v1script = PlutusV1Script( @@ -182,6 +194,11 @@ def _get_script( bytes.fromhex(self.api.script_cbor(script_hash).cbor) ) return _try_fix_script(script_hash, v2script) + elif script_type == "plutusV3": + v3script = PlutusV3Script( + bytes.fromhex(self.api.script_cbor(script_hash).cbor) + ) + return _try_fix_script(script_hash, v3script) else: script_json: JsonDict = self.api.script_json( script_hash, return_type="json" diff --git a/pycardano/backend/kupo.py b/pycardano/backend/kupo.py new file mode 100644 index 00000000..36fa409e --- /dev/null +++ b/pycardano/backend/kupo.py @@ -0,0 +1,255 @@ +from typing import Dict, List, Optional, Tuple, Union + +import requests +from cachetools import Cache, LRUCache, TTLCache + +from pycardano.address import Address +from pycardano.backend.base import ChainContext, GenesisParameters, ProtocolParameters +from pycardano.backend.blockfrost import _try_fix_script +from pycardano.hash import DatumHash, ScriptHash +from pycardano.network import Network +from pycardano.plutus import ( + ExecutionUnits, + PlutusV1Script, + PlutusV2Script, + PlutusV3Script, +) +from pycardano.serialization import RawCBOR +from pycardano.transaction import ( + Asset, + AssetName, + MultiAsset, + TransactionInput, + TransactionOutput, + UTxO, + Value, +) + +__all__ = ["KupoChainContextExtension"] + + +def extract_asset_info(asset_hash: str) -> Tuple[str, ScriptHash, AssetName]: + split_result = asset_hash.split(".") + + if len(split_result) == 1: + policy_hex, asset_name_hex = split_result[0], "" + elif len(split_result) == 2: + policy_hex, asset_name_hex = split_result + else: + raise ValueError(f"Unable to parse asset hash: {asset_hash}") + + policy = ScriptHash.from_primitive(policy_hex) + asset_name = AssetName.from_primitive(asset_name_hex) + + return policy_hex, policy, asset_name + + +class KupoChainContextExtension(ChainContext): + _wrapped_backend: ChainContext + _kupo_url: Optional[str] + _utxo_cache: Cache + _datum_cache: Cache + _refetch_chain_tip_interval: int + + def __init__( + self, + wrapped_backend: ChainContext, + kupo_url: Optional[str] = None, + refetch_chain_tip_interval: int = 10, + utxo_cache_size: int = 1000, + datum_cache_size: int = 1000, + ): + self._kupo_url = kupo_url + self._wrapped_backend = wrapped_backend + self._refetch_chain_tip_interval = refetch_chain_tip_interval + self._utxo_cache = TTLCache( + ttl=self._refetch_chain_tip_interval, maxsize=utxo_cache_size + ) + self._datum_cache = LRUCache(maxsize=datum_cache_size) + + @property + def genesis_param(self) -> GenesisParameters: + """Get chain genesis parameters""" + + return self._wrapped_backend.genesis_param + + @property + def protocol_param(self) -> ProtocolParameters: + """Get current protocol parameters""" + return self._wrapped_backend.protocol_param + + @property + def network(self) -> Network: + """Get current network""" + return self._wrapped_backend.network + + @property + def epoch(self) -> int: + """Current epoch number""" + return self._wrapped_backend.epoch + + @property + def last_block_slot(self) -> int: + """Last block slot""" + return self._wrapped_backend.last_block_slot + + def _utxos(self, address: str) -> List[UTxO]: + """Get all UTxOs associated with an address. + + Args: + address (str): An address encoded with bech32. + + Returns: + List[UTxO]: A list of UTxOs. + """ + key = (self.last_block_slot, address) + if key in self._utxo_cache: + return self._utxo_cache[key] + + if self._kupo_url: + utxos = self._utxos_kupo(address) + else: + utxos = self._wrapped_backend.utxos(address) + + self._utxo_cache[key] = utxos + + return utxos + + def _get_datum_from_kupo(self, datum_hash: str) -> Optional[RawCBOR]: + """Get datum from Kupo. + + Args: + datum_hash (str): A datum hash. + + Returns: + Optional[RawCBOR]: A datum. + """ + datum = self._datum_cache.get(datum_hash, None) + + if datum is not None: + return datum + + if self._kupo_url is None: + raise AssertionError( + "kupo_url object attribute has not been assigned properly." + ) + + kupo_datum_url = self._kupo_url + "/datums/" + datum_hash + datum_result = requests.get(kupo_datum_url).json() + if datum_result and datum_result["datum"] != datum_hash: + datum = RawCBOR(bytes.fromhex(datum_result["datum"])) + + self._datum_cache[datum_hash] = datum + return datum + + def _utxos_kupo(self, address: str) -> List[UTxO]: + """Get all UTxOs associated with an address with Kupo. + Since UTxO querying will be deprecated from Ogmios in next + major release: https://ogmios.dev/mini-protocols/local-state-query/. + + Args: + address (str): An address encoded with bech32. + + Returns: + List[UTxO]: A list of UTxOs. + """ + if self._kupo_url is None: + raise AssertionError( + "kupo_url object attribute has not been assigned properly." + ) + + kupo_utxo_url = self._kupo_url + "/matches/" + address + "?unspent" + results = requests.get(kupo_utxo_url).json() + + utxos = [] + + for result in results: + tx_id = result["transaction_id"] + index = result["output_index"] + + if result["spent_at"] is None: + tx_in = TransactionInput.from_primitive([tx_id, index]) + + lovelace_amount = result["value"]["coins"] + + script = None + script_hash = result.get("script_hash", None) + if script_hash: + kupo_script_url = self._kupo_url + "/scripts/" + script_hash + script = requests.get(kupo_script_url).json() + if script["language"] == "plutus:v3": + script = PlutusV3Script(bytes.fromhex(script["script"])) + script = _try_fix_script(script_hash, script) + elif script["language"] == "plutus:v2": + script = PlutusV2Script(bytes.fromhex(script["script"])) + script = _try_fix_script(script_hash, script) + elif script["language"] == "plutus:v1": + script = PlutusV1Script(bytes.fromhex(script["script"])) + script = _try_fix_script(script_hash, script) + else: + raise ValueError("Unknown plutus script type") + + datum = None + datum_hash = ( + DatumHash.from_primitive(result["datum_hash"]) + if result["datum_hash"] + else None + ) + if datum_hash and result.get("datum_type", "inline"): + datum = self._get_datum_from_kupo(result["datum_hash"]) + + if not result["value"]["assets"]: + tx_out = TransactionOutput( + Address.from_primitive(address), + amount=lovelace_amount, + datum_hash=datum_hash, + datum=datum, + script=script, + ) + else: + multi_assets = MultiAsset() + + for asset, quantity in result["value"]["assets"].items(): + policy_hex, policy, asset_name_hex = extract_asset_info(asset) + multi_assets.setdefault(policy, Asset())[ + asset_name_hex + ] = quantity + + tx_out = TransactionOutput( + Address.from_primitive(address), + amount=Value(lovelace_amount, multi_assets), + datum_hash=datum_hash, + datum=datum, + script=script, + ) + utxos.append(UTxO(tx_in, tx_out)) + else: + continue + + return utxos + + def submit_tx_cbor(self, cbor: Union[bytes, str]): + """Submit a transaction to the blockchain. + + Args: + cbor (Union[bytes, str]): The transaction to be submitted. + + Raises: + :class:`InvalidArgumentException`: When the transaction is invalid. + :class:`TransactionFailedException`: When fails to submit the transaction to blockchain. + """ + return self._wrapped_backend.submit_tx_cbor(cbor) + + def evaluate_tx_cbor(self, cbor: Union[bytes, str]) -> Dict[str, ExecutionUnits]: + """Evaluate execution units of a transaction. + + Args: + cbor (Union[bytes, str]): The serialized transaction to be evaluated. + + Returns: + Dict[str, ExecutionUnits]: A list of execution units calculated for each of the transaction's redeemers + + Raises: + :class:`TransactionFailedException`: When fails to evaluate the transaction. + """ + return self._wrapped_backend.evaluate_tx_cbor(cbor) diff --git a/pycardano/backend/ogmios.py b/pycardano/backend/ogmios_v5.py similarity index 73% rename from pycardano/backend/ogmios.py rename to pycardano/backend/ogmios_v5.py index 63ffaf14..fea3a70b 100644 --- a/pycardano/backend/ogmios.py +++ b/pycardano/backend/ogmios_v5.py @@ -3,9 +3,8 @@ from datetime import datetime, timezone from enum import Enum from fractions import Fraction -from typing import Any, Dict, List, Optional, Tuple, Union +from typing import Any, Dict, List, Optional, Union -import requests import websocket from cachetools import Cache, LRUCache, TTLCache, func @@ -16,15 +15,14 @@ GenesisParameters, ProtocolParameters, ) -from pycardano.backend.blockfrost import _try_fix_script +from pycardano.backend.kupo import KupoChainContextExtension, extract_asset_info from pycardano.exception import TransactionFailedException -from pycardano.hash import DatumHash, ScriptHash +from pycardano.hash import DatumHash from pycardano.network import Network from pycardano.plutus import ExecutionUnits, PlutusV1Script, PlutusV2Script from pycardano.serialization import RawCBOR from pycardano.transaction import ( Asset, - AssetName, MultiAsset, TransactionInput, TransactionOutput, @@ -33,7 +31,7 @@ ) from pycardano.types import JsonDict -__all__ = ["OgmiosChainContext"] +__all__ = ["OgmiosV5ChainContext", "KupoOgmiosV5ChainContext"] class OgmiosQueryType(str, Enum): @@ -42,11 +40,12 @@ class OgmiosQueryType(str, Enum): EvaluateTx = "EvaluateTx" -class OgmiosChainContext(ChainContext): +class OgmiosV5ChainContext(ChainContext): + """Legacy Ogmios Chain Context for Ogmios v5""" + _ws_url: str _network: Network _service_name: str - _kupo_url: Optional[str] _last_known_block_slot: int _last_chain_tip_fetch: float _genesis_param: Optional[GenesisParameters] @@ -59,7 +58,6 @@ def __init__( ws_url: str, network: Network, compact_result=True, - kupo_url=None, refetch_chain_tip_interval: Optional[float] = None, utxo_cache_size: int = 10000, datum_cache_size: int = 10000, @@ -67,7 +65,6 @@ def __init__( self._ws_url = ws_url self._network = network self._service_name = "ogmios.v1:compact" if compact_result else "ogmios" - self._kupo_url = kupo_url self._last_known_block_slot = 0 self._refetch_chain_tip_interval = ( refetch_chain_tip_interval @@ -271,127 +268,12 @@ def _utxos(self, address: str) -> List[UTxO]: if key in self._utxo_cache: return self._utxo_cache[key] - if self._kupo_url: - utxos = self._utxos_kupo(address) - else: - utxos = self._utxos_ogmios(address) + utxos = self._utxos_ogmios(address) self._utxo_cache[key] = utxos return utxos - def _get_datum_from_kupo(self, datum_hash: str) -> Optional[RawCBOR]: - """Get datum from Kupo. - - Args: - datum_hash (str): A datum hash. - - Returns: - Optional[RawCBOR]: A datum. - """ - datum = self._datum_cache.get(datum_hash, None) - - if datum is not None: - return datum - - if self._kupo_url is None: - raise AssertionError( - "kupo_url object attribute has not been assigned properly." - ) - - kupo_datum_url = self._kupo_url + "/datums/" + datum_hash - datum_result = requests.get(kupo_datum_url).json() - if datum_result and datum_result["datum"] != datum_hash: - datum = RawCBOR(bytes.fromhex(datum_result["datum"])) - - self._datum_cache[datum_hash] = datum - return datum - - def _utxos_kupo(self, address: str) -> List[UTxO]: - """Get all UTxOs associated with an address with Kupo. - Since UTxO querying will be deprecated from Ogmios in next - major release: https://ogmios.dev/mini-protocols/local-state-query/. - - Args: - address (str): An address encoded with bech32. - - Returns: - List[UTxO]: A list of UTxOs. - """ - if self._kupo_url is None: - raise AssertionError( - "kupo_url object attribute has not been assigned properly." - ) - - kupo_utxo_url = self._kupo_url + "/matches/" + address + "?unspent" - results = requests.get(kupo_utxo_url).json() - - utxos = [] - - for result in results: - tx_id = result["transaction_id"] - index = result["output_index"] - - if result["spent_at"] is None: - tx_in = TransactionInput.from_primitive([tx_id, index]) - - lovelace_amount = result["value"]["coins"] - - script = None - script_hash = result.get("script_hash", None) - if script_hash: - kupo_script_url = self._kupo_url + "/scripts/" + script_hash - script = requests.get(kupo_script_url).json() - if script["language"] == "plutus:v2": - script = PlutusV2Script(bytes.fromhex(script["script"])) - script = _try_fix_script(script_hash, script) - elif script["language"] == "plutus:v1": - script = PlutusV1Script(bytes.fromhex(script["script"])) - script = _try_fix_script(script_hash, script) - else: - raise ValueError("Unknown plutus script type") - - datum = None - datum_hash = ( - DatumHash.from_primitive(result["datum_hash"]) - if result["datum_hash"] - else None - ) - if datum_hash and result.get("datum_type", "inline"): - datum = self._get_datum_from_kupo(result["datum_hash"]) - - if not result["value"]["assets"]: - tx_out = TransactionOutput( - Address.from_primitive(address), - amount=lovelace_amount, - datum_hash=datum_hash, - datum=datum, - script=script, - ) - else: - multi_assets = MultiAsset() - - for asset, quantity in result["value"]["assets"].items(): - policy_hex, policy, asset_name_hex = self._extract_asset_info( - asset - ) - multi_assets.setdefault(policy, Asset())[ - asset_name_hex - ] = quantity - - tx_out = TransactionOutput( - Address.from_primitive(address), - amount=Value(lovelace_amount, multi_assets), - datum_hash=datum_hash, - datum=datum, - script=script, - ) - utxos.append(UTxO(tx_in, tx_out)) - else: - continue - - return utxos - def _check_utxo_unspent(self, tx_id: str, index: int) -> bool: """Check whether an UTxO is unspent with Ogmios. @@ -402,21 +284,6 @@ def _check_utxo_unspent(self, tx_id: str, index: int) -> bool: results = self._query_utxos_by_tx_id(tx_id, index) return len(results) > 0 - def _extract_asset_info(self, asset_hash: str) -> Tuple[str, ScriptHash, AssetName]: - split_result = asset_hash.split(".") - - if len(split_result) == 1: - policy_hex, asset_name_hex = split_result[0], "" - elif len(split_result) == 2: - policy_hex, asset_name_hex = split_result - else: - raise ValueError(f"Unable to parse asset hash: {asset_hash}") - - policy = ScriptHash.from_primitive(policy_hex) - asset_name = AssetName.from_primitive(asset_name_hex) - - return policy_hex, policy, asset_name - def _utxos_ogmios(self, address: str) -> List[UTxO]: """Get all UTxOs associated with an address with Ogmios. @@ -488,7 +355,7 @@ def _utxo_from_ogmios_result(self, result) -> UTxO: multi_assets = MultiAsset() for asset, quantity in output["value"]["assets"].items(): - policy_hex, policy, asset_name_hex = self._extract_asset_info(asset) + policy_hex, policy, asset_name_hex = extract_asset_info(asset) multi_assets.setdefault(policy, Asset())[asset_name_hex] = quantity tx_out = TransactionOutput( @@ -545,3 +412,25 @@ def evaluate_tx_cbor(self, cbor: Union[bytes, str]) -> Dict[str, ExecutionUnits] result["EvaluationResult"][k]["steps"], ) return result["EvaluationResult"] + + +def KupoOgmiosV5ChainContext( + ws_url: str, + network: Network, + compact_result=True, + refetch_chain_tip_interval: Optional[float] = None, + utxo_cache_size: int = 10000, + datum_cache_size: int = 10000, + kupo_url: Optional[str] = None, +) -> KupoChainContextExtension: + return KupoChainContextExtension( + OgmiosV5ChainContext( + ws_url, + network, + compact_result, + refetch_chain_tip_interval, + utxo_cache_size, + datum_cache_size, + ), + kupo_url, + ) diff --git a/pycardano/backend/ogmios_v6.py b/pycardano/backend/ogmios_v6.py new file mode 100644 index 00000000..7e60f845 --- /dev/null +++ b/pycardano/backend/ogmios_v6.py @@ -0,0 +1,387 @@ +import time +from typing import Dict, List, Optional, Union + +from cachetools import Cache, LRUCache, TTLCache, func +from ogmios.client import Client as OgmiosClient +from ogmios.datatypes import Address as OgmiosAddress +from ogmios.datatypes import Era as OgmiosEra +from ogmios.datatypes import ProtocolParameters as OgmiosProtocolParameters +from ogmios.datatypes import Tip as OgmiosTip +from ogmios.datatypes import TxOutputReference as OgmiosTxOutputReference +from ogmios.datatypes import Utxo as OgmiosUtxo +from ogmios.utils import GenesisParameters as OgmiosGenesisParameters +from ogmios.utils import get_current_era + +from pycardano.address import Address +from pycardano.backend.base import ChainContext, GenesisParameters, ProtocolParameters +from pycardano.backend.kupo import KupoChainContextExtension +from pycardano.hash import DatumHash, ScriptHash +from pycardano.network import Network +from pycardano.plutus import ( + PLUTUS_V1_COST_MODEL, + PLUTUS_V2_COST_MODEL, + ExecutionUnits, + PlutusV1Script, + PlutusV2Script, + PlutusV3Script, +) +from pycardano.serialization import RawCBOR +from pycardano.transaction import ( + Asset, + AssetName, + MultiAsset, + TransactionInput, + TransactionOutput, + UTxO, + Value, +) + +ALONZO_COINS_PER_UTXO_WORD = 34482 +DEFAULT_REFETCH_INTERVAL = 1000 + +__all__ = ["OgmiosV6ChainContext", "OgmiosChainContext", "KupoOgmiosV6ChainContext"] + + +class OgmiosV6ChainContext(ChainContext): + """Ogmios chain context for use with PyCardano""" + + _network: Network + _client: OgmiosClient + _service_name: str + _last_known_block_slot: int + _last_chain_tip_fetch: float + _genesis_param: Optional[GenesisParameters] + _protocol_param: Optional[OgmiosProtocolParameters] + _utxo_cache: Cache + _datum_cache: Cache + + def __init__( + self, + host: str = "localhost", + port: int = 1337, + secure: bool = False, + refetch_chain_tip_interval: Optional[float] = None, + utxo_cache_size: int = 10000, + datum_cache_size: int = 10000, + network: Network = Network.TESTNET, + ): + self.host = host + self.port = port + self.secure = secure + self._network = network + self._service_name = "ogmios" + self._last_known_block_slot = 0 + self._refetch_chain_tip_interval = ( + refetch_chain_tip_interval + if refetch_chain_tip_interval is not None + else DEFAULT_REFETCH_INTERVAL + ) + self._last_chain_tip_fetch = 0 + self._genesis_param = None + self._protocol_param = None + + self._utxo_cache = TTLCache( + ttl=self._refetch_chain_tip_interval, maxsize=utxo_cache_size + ) + self._datum_cache = LRUCache(maxsize=datum_cache_size) + + def _query_current_era(self) -> OgmiosEra: + with OgmiosClient(self.host, self.port, self.secure) as client: + return get_current_era(client) + + def _query_current_epoch(self) -> int: + with OgmiosClient(self.host, self.port, self.secure) as client: + epoch, _ = client.query_epoch.execute() + return epoch + + def _query_chain_tip(self) -> OgmiosTip: + with OgmiosClient(self.host, self.port, self.secure) as client: + tip, _ = client.query_network_tip.execute() + return tip + + def _query_utxos_by_address(self, address: Address) -> List[OgmiosUtxo]: + with OgmiosClient(self.host, self.port, self.secure) as client: + utxos, _ = client.query_utxo.execute([address]) + return utxos + + def _query_utxos_by_tx_id(self, tx_id: str, index: int) -> List[OgmiosUtxo]: + with OgmiosClient(self.host, self.port, self.secure) as client: + utxos, _ = client.query_utxo.execute( + [OgmiosTxOutputReference(tx_id, index)] + ) + return utxos + + def _is_chain_tip_updated(self): + # fetch at most every twenty seconds! + if time.time() - self._last_chain_tip_fetch < self._refetch_chain_tip_interval: + return False + self._last_chain_tip_fetch = time.time() + slot = self.last_block_slot + if self._last_known_block_slot < slot: + self._last_known_block_slot = slot + return True + else: + return False + + @staticmethod + def _fraction_parser(fraction: str) -> float: + x, y = fraction.split("/") + return int(x) / int(y) + + @property + def protocol_param(self) -> ProtocolParameters: + if not self._protocol_param or self._is_chain_tip_updated(): + self._protocol_param = self._fetch_protocol_param() + return self._protocol_param + + def _fetch_protocol_param(self) -> ProtocolParameters: + with OgmiosClient(self.host, self.port, self.secure) as client: + protocol_parameters, _ = client.query_protocol_parameters.execute() + pyc_protocol_params = ProtocolParameters( + min_fee_constant=protocol_parameters.min_fee_constant.lovelace, + min_fee_coefficient=protocol_parameters.min_fee_coefficient, + min_pool_cost=protocol_parameters.min_stake_pool_cost.lovelace, + max_block_size=protocol_parameters.max_block_body_size.get("bytes"), + max_tx_size=protocol_parameters.max_transaction_size.get("bytes"), + max_block_header_size=protocol_parameters.max_block_header_size.get( + "bytes" + ), + key_deposit=protocol_parameters.stake_credential_deposit.lovelace, + pool_deposit=protocol_parameters.stake_pool_deposit.lovelace, + pool_influence=eval(protocol_parameters.stake_pool_pledge_influence), + monetary_expansion=eval(protocol_parameters.monetary_expansion), + treasury_expansion=eval(protocol_parameters.treasury_expansion), + decentralization_param=None, # type: ignore[arg-type] + extra_entropy=protocol_parameters.extra_entropy, + protocol_major_version=protocol_parameters.version.get("major"), + protocol_minor_version=protocol_parameters.version.get("minor"), + min_utxo=None, # type: ignore[arg-type] + price_mem=eval( + protocol_parameters.script_execution_prices.get("memory") + ), + price_step=eval(protocol_parameters.script_execution_prices.get("cpu")), + max_tx_ex_mem=protocol_parameters.max_execution_units_per_transaction.get( + "memory" + ), + max_tx_ex_steps=protocol_parameters.max_execution_units_per_transaction.get( + "cpu" + ), + max_block_ex_mem=protocol_parameters.max_execution_units_per_block.get( + "memory" + ), + max_block_ex_steps=protocol_parameters.max_execution_units_per_block.get( + "cpu" + ), + max_val_size=protocol_parameters.max_value_size.get("bytes"), + collateral_percent=protocol_parameters.collateral_percentage, + max_collateral_inputs=protocol_parameters.max_collateral_inputs, + coins_per_utxo_word=ALONZO_COINS_PER_UTXO_WORD, + coins_per_utxo_byte=protocol_parameters.min_utxo_deposit_coefficient, + cost_models=self._parse_cost_models( + protocol_parameters.plutus_cost_models + ), + maximum_reference_scripts_size=protocol_parameters.max_ref_script_size, + min_fee_reference_scripts=protocol_parameters.min_fee_ref_scripts, + ) + return pyc_protocol_params + + @property + def genesis_param(self) -> GenesisParameters: + if not self._genesis_param or self._is_chain_tip_updated(): + # TODO transform to PyCardano GenesisParameters? + self._genesis_param = self._fetch_genesis_param() # type: ignore[assignment] + + # Update the refetch interval if we haven't calculated it yet + if ( + self._refetch_chain_tip_interval == DEFAULT_REFETCH_INTERVAL + and self._genesis_param is not None + and self._genesis_param.slot_length is not None + and self._genesis_param.active_slots_coefficient is not None + ): + self._refetch_chain_tip_interval = ( + self._genesis_param.slot_length + / float(self._genesis_param.active_slots_coefficient) + ) + return self._genesis_param # type: ignore[return-value] + + def _fetch_genesis_param(self) -> OgmiosGenesisParameters: + with OgmiosClient(self.host, self.port, self.secure) as client: + return OgmiosGenesisParameters(client, self._query_current_era()) + + @property + def network(self) -> Network: + return self._network + + @property + def epoch(self) -> int: + return self._query_current_epoch() + + @property + @func.ttl_cache(ttl=1) + def last_block_slot(self) -> int: + tip = self._query_chain_tip() + return tip.slot + + def _utxos(self, address: str) -> List[UTxO]: + key = (self.last_block_slot, address) + if key in self._utxo_cache: + return self._utxo_cache[key] + + utxos = self._utxos_ogmios(OgmiosAddress(address=address)) + + self._utxo_cache[key] = utxos + + return utxos + + def _check_utxo_unspent(self, tx_id: str, index: int) -> bool: + results = self._query_utxos_by_tx_id(tx_id, index) + return len(results) > 0 + + def _utxos_ogmios(self, address: Address) -> List[OgmiosUtxo]: + """Get all UTxOs associated with an address with Ogmios. + + Args: + address (str): An address encoded with bech32. + + Returns: + List[UTxO]: A list of UTxOs. + """ + results = self._query_utxos_by_address(address) + + utxos = [] + for result in results: + utxos.append(self._utxo_from_ogmios_result(result)) + + return utxos + + def _utxo_from_ogmios_result(self, utxo: OgmiosUtxo) -> UTxO: + """Convert an Ogmios UTxO result to a PyCardano UTxO.""" + tx_in = TransactionInput.from_primitive([utxo.tx_id, utxo.index]) + lovelace_amount = utxo.value.get("ada").get("lovelace", 0) + script = utxo.script + if script: + # TODO: Need to test with native scripts + if script["language"] == "plutus:v3": + script = PlutusV3Script(bytes.fromhex(script["cbor"])) + if script["language"] == "plutus:v2": + script = PlutusV2Script(bytes.fromhex(script["cbor"])) + elif script["language"] == "plutus:v1": + script = PlutusV1Script(bytes.fromhex(script["cbor"])) + else: + raise ValueError("Unknown plutus script type") + datum_hash = ( + DatumHash.from_primitive(utxo.datum_hash) if utxo.datum_hash else None + ) + datum = None + if utxo.datum and utxo.datum != utxo.datum_hash: + datum = RawCBOR(bytes.fromhex(utxo.datum)) + if set(utxo.value.keys()) == {"ada"}: + tx_out = TransactionOutput( + Address.from_primitive(utxo.address), + amount=lovelace_amount, + datum_hash=datum_hash, + datum=datum, + script=script, + ) + else: + multi_assets = MultiAsset() + for asset_hex, token in utxo.value.items(): + if asset_hex != "ada": + for token_name_hex, quantity in token.items(): + policy = ScriptHash.from_primitive(asset_hex) + token_name = AssetName.from_primitive(token_name_hex) + multi_assets.setdefault(policy, Asset())[token_name] = quantity + + tx_out = TransactionOutput( + Address.from_primitive(utxo.address), + amount=Value(lovelace_amount, multi_assets), + datum_hash=datum_hash, + datum=datum, + script=script, + ) + pyc_utxo = UTxO(tx_in, tx_out) + return pyc_utxo + + def utxo_by_tx_id(self, tx_id: str, index: int) -> Optional[UTxO]: + utxos = self._query_utxos_by_tx_id(tx_id, index) + if len(utxos) > 0: + return self._utxo_from_ogmios_result(utxos[0]) + return None + + def submit_tx_cbor(self, cbor: Union[bytes, str]): + if isinstance(cbor, bytes): + cbor = cbor.hex() + with OgmiosClient(self.host, self.port, self.secure) as client: + client.submit_transaction.execute(cbor) + + def evaluate_tx_cbor(self, cbor: Union[bytes, str]) -> Dict[str, ExecutionUnits]: + if isinstance(cbor, bytes): + cbor = cbor.hex() + with OgmiosClient(self.host, self.port, self.secure) as client: + result, _ = client.evaluate_transaction.execute(cbor) + result_dict = {} + for res in result: + purpose = res["validator"]["purpose"] + # Hotfix: this purpose has been renamed in the latest version of Ogmios + if purpose == "withdraw": + purpose = "withdrawal" + result_dict[f"{purpose}:{res['validator']['index']}"] = ExecutionUnits( + mem=res["budget"]["memory"], + steps=res["budget"]["cpu"], + ) + return result_dict + + def _parse_cost_models(self, plutus_cost_models): + ogmios_cost_models = plutus_cost_models or {} + + cost_models = {} + if "plutus:v1" in ogmios_cost_models: + cost_models["PlutusV1"] = dict( + zip( + sorted(PLUTUS_V1_COST_MODEL.keys()), + ogmios_cost_models["plutus:v1"].copy(), + ) + ) + if "plutus:v2" in ogmios_cost_models: + cost_models["PlutusV2"] = dict( + zip( + sorted(PLUTUS_V2_COST_MODEL.keys()), + ogmios_cost_models["plutus:v2"].copy(), + ) + ) + if "plutus:v3" in ogmios_cost_models: + cost_models["PlutusV3"] = {} + width = len(f'{len(ogmios_cost_models["plutus:v3"])}') + for i, v in enumerate(ogmios_cost_models["plutus:v3"].copy()): + cost_models["PlutusV3"][f"{i:0{width}d}"] = v + return cost_models + + +class OgmiosChainContext(OgmiosV6ChainContext): + """An alias of OgmiosV6ChainContext for backwards compatibility.""" + + pass + + +def KupoOgmiosV6ChainContext( + host: str, + port: int, + secure: bool, + refetch_chain_tip_interval: Optional[float] = None, + utxo_cache_size: int = 10000, + datum_cache_size: int = 10000, + network: Network = Network.TESTNET, + kupo_url: Optional[str] = None, +) -> KupoChainContextExtension: + return KupoChainContextExtension( + OgmiosV6ChainContext( + host, + port, + secure, + refetch_chain_tip_interval, + utxo_cache_size, + datum_cache_size, + network, + ), + kupo_url, + ) diff --git a/pycardano/metadata.py b/pycardano/metadata.py index 6ddfa708..17bb4a08 100644 --- a/pycardano/metadata.py +++ b/pycardano/metadata.py @@ -10,6 +10,7 @@ from pycardano.exception import DeserializeException, InvalidArgumentException from pycardano.hash import AUXILIARY_DATA_HASH_SIZE, AuxiliaryDataHash from pycardano.nativescript import NativeScript +from pycardano.plutus import PlutusV1Script, PlutusV2Script, PlutusV3Script from pycardano.serialization import ( ArrayCBORSerializable, CBORSerializable, @@ -87,9 +88,15 @@ class AlonzoMetadata(MapCBORSerializable): default=None, metadata={"optional": True, "key": 1, "object_hook": list_hook(NativeScript)}, ) - plutus_scripts: Optional[List[bytes]] = field( + plutus_v1_scripts: Optional[List[PlutusV1Script]] = field( default=None, metadata={"optional": True, "key": 2} ) + plutus_v2_scripts: Optional[List[PlutusV2Script]] = field( + default=None, metadata={"optional": True, "key": 3} + ) + plutus_v3_scripts: Optional[List[PlutusV3Script]] = field( + default=None, metadata={"optional": True, "key": 4} + ) def to_primitive(self) -> Primitive: return CBORTag(AlonzoMetadata.TAG, super(AlonzoMetadata, self).to_primitive()) diff --git a/pycardano/plutus.py b/pycardano/plutus.py index b1ee6e81..87172c63 100644 --- a/pycardano/plutus.py +++ b/pycardano/plutus.py @@ -8,12 +8,13 @@ from dataclasses import dataclass, field, fields from enum import Enum from hashlib import sha256 -from typing import Any, Optional, Type, Union +from typing import Any, List, Optional, Type, Union import cbor2 from cbor2 import CBORTag from nacl.encoding import RawEncoder from nacl.hash import blake2b +from typeguard import typechecked from pycardano.exception import DeserializeException, InvalidArgumentException from pycardano.hash import DATUM_HASH_SIZE, SCRIPT_HASH_SIZE, DatumHash, ScriptHash @@ -41,8 +42,13 @@ "ExecutionUnits", "PlutusV1Script", "PlutusV2Script", + "PlutusV3Script", "RawPlutusData", "Redeemer", + "RedeemerKey", + "RedeemerValue", + "RedeemerMap", + "Redeemers", "ScriptType", "datum_hash", "plutus_script_hash", @@ -992,6 +998,57 @@ def from_primitive(cls: Type[Redeemer], values: list) -> Redeemer: return redeemer +@dataclass(repr=False) +class RedeemerKey(ArrayCBORSerializable): + tag: RedeemerTag + + index: int = field(default=0) + + @classmethod + @limit_primitive_type(list, tuple) + def from_primitive(cls: Type[RedeemerKey], values: list) -> RedeemerKey: + tag = RedeemerTag.from_primitive(values[0]) + index = values[1] + return cls(tag, index) + + def __eq__(self, other): + if not isinstance(other, RedeemerKey): + return False + return self.tag == other.tag and self.index == other.index + + def __hash__(self): + return hash(self.to_cbor()) + + +@dataclass(repr=False) +class RedeemerValue(ArrayCBORSerializable): + data: Any + + ex_units: ExecutionUnits + + @classmethod + @limit_primitive_type(list) + def from_primitive(cls: Type[RedeemerValue], values: list) -> RedeemerValue: + if isinstance(values[0], CBORTag) and cls is RedeemerValue: + values[0] = RawPlutusData.from_primitive(values[0]) + return super(RedeemerValue, cls).from_primitive([values[0], values[1]]) + + def __eq__(self, other): + if not isinstance(other, RedeemerValue): + return False + return self.data == other.data and self.ex_units == other.ex_units + + +@typechecked +class RedeemerMap(DictCBORSerializable): + KEY_TYPE = RedeemerKey + + VALUE_TYPE = RedeemerValue + + +Redeemers = Union[List[Redeemer], RedeemerMap] + + def plutus_script_hash( script: Union[bytes, PlutusV1Script, PlutusV2Script] ) -> ScriptHash: @@ -1014,6 +1071,10 @@ class PlutusV2Script(bytes): pass +class PlutusV3Script(bytes): + pass + + ScriptType = Union[bytes, NativeScript, PlutusV1Script, PlutusV2Script] """Script type. A Union type that contains all valid script types.""" @@ -1037,6 +1098,10 @@ def script_hash(script: ScriptType) -> ScriptHash: return ScriptHash( blake2b(bytes.fromhex("02") + script, SCRIPT_HASH_SIZE, encoder=RawEncoder) ) + elif isinstance(script, PlutusV3Script): + return ScriptHash( + blake2b(bytes.fromhex("03") + script, SCRIPT_HASH_SIZE, encoder=RawEncoder) + ) else: raise TypeError(f"Unexpected script type: {type(script)}") diff --git a/pycardano/transaction.py b/pycardano/transaction.py index 79b7ce01..5d5c7c0e 100644 --- a/pycardano/transaction.py +++ b/pycardano/transaction.py @@ -28,14 +28,22 @@ from pycardano.metadata import AuxiliaryData from pycardano.nativescript import NativeScript from pycardano.network import Network -from pycardano.plutus import Datum, PlutusV1Script, PlutusV2Script, RawPlutusData +from pycardano.plutus import ( + Datum, + PlutusV1Script, + PlutusV2Script, + PlutusV3Script, + RawPlutusData, +) from pycardano.serialization import ( ArrayCBORSerializable, CBORSerializable, + DictBase, DictCBORSerializable, MapCBORSerializable, Primitive, default_encoder, + limit_primitive_type, list_hook, ) from pycardano.types import typechecked @@ -81,6 +89,13 @@ class Asset(DictCBORSerializable): VALUE_TYPE = int + def normalize(self) -> Asset: + """Normalize the Asset by removing zero values.""" + for k, v in list(self.items()): + if v == 0: + self.pop(k) + return self + def union(self, other: Asset) -> Asset: return self + other @@ -88,18 +103,18 @@ def __add__(self, other: Asset) -> Asset: new_asset = deepcopy(self) for n in other: new_asset[n] = new_asset.get(n, 0) + other[n] - return new_asset + return new_asset.normalize() def __iadd__(self, other: Asset) -> Asset: new_item = self + other - self.update(new_item) - return self + self.data = new_item.data + return self.normalize() def __sub__(self, other: Asset) -> Asset: new_asset = deepcopy(self) for n in other: new_asset[n] = new_asset.get(n, 0) - other[n] - return new_asset + return new_asset.normalize() def __eq__(self, other): if not isinstance(other, Asset): @@ -118,6 +133,20 @@ def __le__(self, other: Asset) -> bool: return False return True + @classmethod + @limit_primitive_type(dict) + def from_primitive(cls: Type[DictBase], value: dict) -> DictBase: + res = super().from_primitive(value) + # pop zero values + for n, v in list(res.items()): + if v == 0: + res.pop(n) + return res + + def to_shallow_primitive(self) -> dict: + x = deepcopy(self).normalize() + return super(self.__class__, x).to_shallow_primitive() + @typechecked class MultiAsset(DictCBORSerializable): @@ -128,22 +157,30 @@ class MultiAsset(DictCBORSerializable): def union(self, other: MultiAsset) -> MultiAsset: return self + other + def normalize(self) -> MultiAsset: + """Normalize the MultiAsset by removing zero values.""" + for k, v in list(self.items()): + v.normalize() + if len(v) == 0: + self.pop(k) + return self + def __add__(self, other): new_multi_asset = deepcopy(self) for p in other: new_multi_asset[p] = new_multi_asset.get(p, Asset()) + other[p] - return new_multi_asset + return new_multi_asset.normalize() def __iadd__(self, other): new_item = self + other - self.update(new_item) - return self + self.data = new_item.data + return self.normalize() def __sub__(self, other: MultiAsset) -> MultiAsset: new_multi_asset = deepcopy(self) for p in other: new_multi_asset[p] = new_multi_asset.get(p, Asset()) - other[p] - return new_multi_asset + return new_multi_asset.normalize() def __eq__(self, other): if not isinstance(other, MultiAsset): @@ -203,6 +240,20 @@ def count(self, criteria=Callable[[ScriptHash, AssetName, int], bool]) -> int: return count + @classmethod + @limit_primitive_type(dict) + def from_primitive(cls: Type[DictBase], value: dict) -> DictBase: + res = super().from_primitive(value) + # pop empty values + for n, v in list(res.items()): + if not v: + res.pop(n) + return res + + def to_shallow_primitive(self) -> dict: + x = deepcopy(self).normalize() + return super(self.__class__, x).to_shallow_primitive() + @typechecked @dataclass(repr=False) @@ -259,15 +310,17 @@ def to_shallow_primitive(self): class _Script(ArrayCBORSerializable): _TYPE: int = field(init=False, default=0) - script: Union[NativeScript, PlutusV1Script, PlutusV2Script] + script: Union[NativeScript, PlutusV1Script, PlutusV2Script, PlutusV3Script] def __post_init__(self): if isinstance(self.script, NativeScript): self._TYPE = 0 elif isinstance(self.script, PlutusV1Script): self._TYPE = 1 - else: + elif isinstance(self.script, PlutusV2Script): self._TYPE = 2 + else: + self._TYPE = 3 @classmethod def from_primitive(cls: Type[_Script], values: List[Primitive]) -> _Script: @@ -276,8 +329,10 @@ def from_primitive(cls: Type[_Script], values: List[Primitive]) -> _Script: assert isinstance(values[1], bytes) if values[0] == 1: return cls(PlutusV1Script(values[1])) - else: + elif values[0] == 2: return cls(PlutusV2Script(values[1])) + else: + return cls(PlutusV3Script(values[1])) @dataclass(repr=False) @@ -344,7 +399,9 @@ class _TransactionOutputPostAlonzo(MapCBORSerializable): ) @property - def script(self) -> Optional[Union[NativeScript, PlutusV1Script, PlutusV2Script]]: + def script( + self, + ) -> Optional[Union[NativeScript, PlutusV1Script, PlutusV2Script, PlutusV3Script]]: if self.script_ref: return self.script_ref.script.script else: @@ -370,7 +427,9 @@ class TransactionOutput(CBORSerializable): datum: Optional[Datum] = None - script: Optional[Union[NativeScript, PlutusV1Script, PlutusV2Script]] = None + script: Optional[ + Union[NativeScript, PlutusV1Script, PlutusV2Script, PlutusV3Script] + ] = None post_alonzo: Optional[bool] = False diff --git a/pycardano/txbuilder.py b/pycardano/txbuilder.py index 63ea93cc..b2a7e854 100644 --- a/pycardano/txbuilder.py +++ b/pycardano/txbuilder.py @@ -4,6 +4,7 @@ from dataclasses import dataclass, field, fields from typing import Dict, List, Optional, Set, Tuple, Union +from pycardano import RedeemerMap from pycardano.address import Address, AddressType from pycardano.backend.base import ChainContext from pycardano.certificate import ( @@ -40,8 +41,12 @@ ExecutionUnits, PlutusV1Script, PlutusV2Script, + PlutusV3Script, Redeemer, + RedeemerKey, + Redeemers, RedeemerTag, + RedeemerValue, ScriptType, datum_hash, script_hash, @@ -119,6 +124,9 @@ class TransactionBuilder: initial_stake_pool_registration: Optional[bool] = field(default=False) + use_redeemer_map: Optional[bool] = field(default=True) + """Whether to serialize redeemers as a map or a list. Default is True.""" + _inputs: List[UTxO] = field(init=False, default_factory=lambda: []) _potential_inputs: List[UTxO] = field(init=False, default_factory=lambda: []) @@ -155,9 +163,9 @@ class TransactionBuilder: init=False, default_factory=lambda: {} ) - _reference_scripts: List[Union[NativeScript, PlutusV1Script, PlutusV2Script]] = ( - field(init=False, default_factory=lambda: []) - ) + _reference_scripts: List[ + Union[NativeScript, PlutusV1Script, PlutusV2Script, PlutusV3Script] + ] = field(init=False, default_factory=lambda: []) _should_estimate_execution_units: Optional[bool] = field(init=False, default=None) @@ -185,7 +193,7 @@ def _consolidate_redeemer(self, redeemer): raise InvalidArgumentException( f"All redeemers need to provide execution units if the firstly " f"added redeemer specifies execution units. \n" - f"Added redeemers: {self.redeemers} \n" + f"Added redeemers: {self._redeemer_list} \n" f"New redeemer: {redeemer}" ) if self._should_estimate_execution_units: @@ -193,7 +201,7 @@ def _consolidate_redeemer(self, redeemer): raise InvalidArgumentException( f"No redeemer should provide execution units if the firstly " f"added redeemer didn't provide execution units. \n" - f"Added redeemers: {self.redeemers} \n" + f"Added redeemers: {self._redeemer_list} \n" f"New redeemer: {redeemer}" ) else: @@ -203,7 +211,7 @@ def add_script_input( self, utxo: UTxO, script: Optional[ - Union[UTxO, NativeScript, PlutusV1Script, PlutusV2Script] + Union[UTxO, NativeScript, PlutusV1Script, PlutusV2Script, PlutusV3Script] ] = None, datum: Optional[Datum] = None, redeemer: Optional[Redeemer] = None, @@ -212,7 +220,8 @@ def add_script_input( Args: utxo (UTxO): Script UTxO to be added. - script (Optional[Union[UTxO, NativeScript, PlutusV1Script, PlutusV2Script]]): A plutus script. + script (Optional[Union[UTxO, NativeScript, PlutusV1Script, PlutusV2Script, PlutusV3Script]]): + A plutus script. If not provided, the script will be inferred from the input UTxO (first arg of this method). The script can also be a specific UTxO whose output contains an inline script. datum (Optional[Datum]): A plutus datum to unlock the UTxO. @@ -263,7 +272,10 @@ def add_script_input( # collect potential scripts to fulfill the input candidate_scripts: List[ - Tuple[Union[NativeScript, PlutusV1Script, PlutusV2Script], Optional[UTxO]] + Tuple[ + Union[NativeScript, PlutusV1Script, PlutusV2Script, PlutusV3Script], + Optional[UTxO], + ] ] = [] if utxo.output.script: candidate_scripts.append((utxo.output.script, utxo)) @@ -285,11 +297,14 @@ def add_script_input( for candidate_script, candidate_utxo in candidate_scripts: if script_hash(candidate_script) != input_script_hash: continue + found_valid_script = True self._inputs_to_scripts[utxo] = candidate_script - if candidate_utxo is not None: + + if candidate_utxo is not None and candidate_utxo != utxo: self.reference_inputs.add(candidate_utxo) self._reference_scripts.append(candidate_script) + break if not found_valid_script: raise InvalidArgumentException( f"Cannot find a valid script to fulfill the input UTxO: {utxo.input}." @@ -301,13 +316,15 @@ def add_script_input( def add_minting_script( self, - script: Union[UTxO, NativeScript, PlutusV1Script, PlutusV2Script], + script: Union[ + UTxO, NativeScript, PlutusV1Script, PlutusV2Script, PlutusV3Script + ], redeemer: Optional[Redeemer] = None, ) -> TransactionBuilder: """Add a minting script along with its datum and redeemer to this transaction. Args: - script (Union[UTxO, PlutusV1Script, PlutusV2Script]): A plutus script. + script (Union[UTxO, PlutusV1Script, PlutusV2Script, PlutusV3Script]): A plutus script. redeemer (Optional[Redeemer]): A plutus redeemer to unlock the UTxO. Returns: @@ -333,13 +350,15 @@ def add_minting_script( def add_withdrawal_script( self, - script: Union[UTxO, NativeScript, PlutusV1Script, PlutusV2Script], + script: Union[ + UTxO, NativeScript, PlutusV1Script, PlutusV2Script, PlutusV3Script + ], redeemer: Optional[Redeemer] = None, ) -> TransactionBuilder: """Add a withdrawal script along with its redeemer to this transaction. Args: - script (Union[UTxO, PlutusV1Script, PlutusV2Script]): A plutus script. + script (Union[UTxO, PlutusV1Script, PlutusV2Script, PlutusV3Script]): A plutus script. redeemer (Optional[Redeemer]): A plutus redeemer to unlock the UTxO. Returns: @@ -473,16 +492,38 @@ def datums(self) -> Dict[DatumHash, Datum]: return self._datums @property - def redeemers(self) -> List[Redeemer]: + def _redeemer_list(self) -> List[Redeemer]: return ( [r for r in self._inputs_to_redeemers.values() if r is not None] + [r for _, r in self._minting_script_to_redeemers if r is not None] + [r for _, r in self._withdrawal_script_to_redeemers if r is not None] ) + def redeemers(self) -> Redeemers: + redeemer_list = self._redeemer_list + + # We have to serialize redeemers as a map if there are no redeemers + if self.use_redeemer_map or not redeemer_list: + redeemers = RedeemerMap() + for r in redeemer_list: + if r.tag is None: + raise InvalidArgumentException( + f"Redeemer tag is not set. Redeemer: {r}" + ) + if r.ex_units is None: + raise InvalidArgumentException( + f"Execution units are not set. Redeemer: {r}" + ) + k = RedeemerKey(r.tag, r.index) + v = RedeemerValue(r.data, r.ex_units) + redeemers[k] = v + return redeemers + else: + return redeemer_list + @property def script_data_hash(self) -> Optional[ScriptDataHash]: - if self.datums or self.redeemers: + if self.datums or self._redeemer_list: cost_models = {} for s in self.all_scripts: if isinstance(s, PlutusV1Script) or type(s) is bytes: @@ -495,8 +536,12 @@ def script_data_hash(self) -> Optional[ScriptDataHash]: self.context.protocol_param.cost_models.get("PlutusV2") or PLUTUS_V2_COST_MODEL ) + if isinstance(s, PlutusV3Script): + cost_models[2] = self.context.protocol_param.cost_models.get( + "PlutusV3", {} + ) return script_data_hash( - self.redeemers, list(self.datums.values()), CostModels(cost_models) + self.redeemers(), list(self.datums.values()), CostModels(cost_models) ) else: return None @@ -511,8 +556,10 @@ def _calc_change( provided = Value() for i in inputs: provided += i.output.amount + if self.mint: provided.multi_asset += self.mint + if self.withdrawals: for v in self.withdrawals.values(): provided.coin += v @@ -862,7 +909,7 @@ def _set_redeemer_index(self): script_staking_credential.to_primitive() ) - self.redeemers.sort(key=lambda r: r.index) + self._redeemer_list.sort(key=lambda r: r.index) def _build_tx_body(self) -> TransactionBody: tx_body = TransactionBody( @@ -875,7 +922,7 @@ def _build_tx_body(self) -> TransactionBody: self.auxiliary_data.hash() if self.auxiliary_data else None ), script_data_hash=self.script_data_hash, - required_signers=self.required_signers, + required_signers=self.required_signers if self.required_signers else None, validity_start=self.validity_start, collateral=( [c.input for c in self.collaterals] if self.collaterals else None @@ -892,12 +939,16 @@ def _build_tx_body(self) -> TransactionBody: ) return tx_body - def _build_fake_vkey_witnesses(self) -> List[VerificationKeyWitness]: + def _build_required_vkeys(self) -> Set[VerificationKeyHash]: vkey_hashes = self._input_vkey_hashes() vkey_hashes.update(self._required_signer_vkey_hashes()) vkey_hashes.update(self._native_scripts_vkey_hashes()) vkey_hashes.update(self._certificate_vkey_hashes()) vkey_hashes.update(self._withdrawal_vkey_hashes()) + return vkey_hashes + + def _build_fake_vkey_witnesses(self) -> List[VerificationKeyWitness]: + vkey_hashes = self._build_required_vkeys() witness_count = self.witness_override or len(vkey_hashes) @@ -930,10 +981,16 @@ def _build_full_fake_tx(self) -> Transaction: ) return tx - def build_witness_set(self) -> TransactionWitnessSet: + def build_witness_set( + self, remove_dup_script: bool = False + ) -> TransactionWitnessSet: """Build a transaction witness set, excluding verification key witnesses. This function is especially useful when the transaction involves Plutus scripts. + Args: + remove_dup_script (bool): Whether to remove scripts, that are already attached to inputs, + from the witness set. + Returns: TransactionWitnessSet: A transaction witness set without verification key witnesses. """ @@ -941,26 +998,41 @@ def build_witness_set(self) -> TransactionWitnessSet: native_scripts: List[NativeScript] = [] plutus_v1_scripts: List[PlutusV1Script] = [] plutus_v2_scripts: List[PlutusV2Script] = [] + plutus_v3_scripts: List[PlutusV3Script] = [] + + input_scripts = ( + { + script_hash(i.output.script) + for i in self.inputs + if i.output.script is not None + } + if remove_dup_script + else {} + ) for script in self.scripts: - if isinstance(script, NativeScript): - native_scripts.append(script) - elif isinstance(script, PlutusV1Script): - plutus_v1_scripts.append(script) - elif type(script) is bytes: - plutus_v1_scripts.append(PlutusV1Script(script)) - elif isinstance(script, PlutusV2Script): - plutus_v2_scripts.append(script) - else: - raise InvalidArgumentException( - f"Unsupported script type: {type(script)}" - ) + if script_hash(script) not in input_scripts: + if isinstance(script, NativeScript): + native_scripts.append(script) + elif isinstance(script, PlutusV1Script): + plutus_v1_scripts.append(script) + elif type(script) is bytes: + plutus_v1_scripts.append(PlutusV1Script(script)) + elif isinstance(script, PlutusV2Script): + plutus_v2_scripts.append(script) + elif isinstance(script, PlutusV3Script): + plutus_v3_scripts.append(script) + else: + raise InvalidArgumentException( + f"Unsupported script type: {type(script)}" + ) return TransactionWitnessSet( native_scripts=native_scripts if native_scripts else None, plutus_v1_script=plutus_v1_scripts if plutus_v1_scripts else None, plutus_v2_script=plutus_v2_scripts if plutus_v2_scripts else None, - redeemer=self.redeemers if self.redeemers else None, + plutus_v3_script=plutus_v3_scripts if plutus_v3_scripts else None, + redeemer=self.redeemers() if self._redeemer_list else None, plutus_data=list(self.datums.values()) if self.datums else None, ) @@ -972,9 +1044,18 @@ def _ensure_no_input_exclusion_conflict(self): f"{intersection}." ) + def _ref_script_size(self): + ref_script_size = 0 + for s in self._reference_scripts: + if isinstance(s, NativeScript): + ref_script_size += len(s.to_cbor()) + else: + ref_script_size += len(s) + return ref_script_size + def _estimate_fee(self): plutus_execution_units = ExecutionUnits(0, 0) - for redeemer in self.redeemers: + for redeemer in self._redeemer_list: plutus_execution_units += redeemer.ex_units estimated_fee = fee( @@ -982,6 +1063,7 @@ def _estimate_fee(self): len(self._build_full_fake_tx().to_cbor()), plutus_execution_units.steps, plutus_execution_units.mem, + self._ref_script_size(), ) if self.fee_buffer is not None: estimated_fee += self.fee_buffer @@ -1228,6 +1310,7 @@ def _set_collateral_return(self, collateral_return_address: Optional[Address]): if ( not witnesses.plutus_v1_script and not witnesses.plutus_v2_script + and not witnesses.plutus_v3_script and not self._reference_scripts ): return @@ -1236,7 +1319,7 @@ def _set_collateral_return(self, collateral_return_address: Optional[Address]): return collateral_amount = ( - max_tx_fee(context=self.context) + max_tx_fee(context=self.context, ref_script_size=self._ref_script_size()) * self.context.protocol_param.collateral_percent // 100 ) @@ -1313,7 +1396,7 @@ def _update_execution_units( estimated_execution_units = self._estimate_execution_units( change_address, merge_change, collateral_change_address ) - for r in self.redeemers: + for r in self._redeemer_list: assert ( r.tag is not None ), "Expected tag of redeemer to be set, but found None" @@ -1367,6 +1450,7 @@ def build_and_sign( auto_validity_start_offset: Optional[int] = None, auto_ttl_offset: Optional[int] = None, auto_required_signers: Optional[bool] = None, + force_skeys: Optional[bool] = False, ) -> Transaction: """Build a transaction body from all constraints set through the builder and sign the transaction with provided signing keys. @@ -1388,6 +1472,10 @@ def build_and_sign( auto_required_signers (Optional[bool]): Automatically add all pubkeyhashes of transaction inputs and the given signers to required signatories (default only for Smart Contract transactions). Manually set required signers will always take precedence. + force_skeys (Optional[bool]): Whether to force the use of signing keys for signing the transaction. + Default is False, which means that provided signing keys will only be used to sign the transaction if + they are actually required by the transaction. This is useful to reduce tx fees by not including + unnecessary signatures. If set to True, all provided signing keys will be used to sign the transaction. Returns: Transaction: A signed transaction. @@ -1406,13 +1494,24 @@ def build_and_sign( auto_ttl_offset=auto_ttl_offset, auto_required_signers=auto_required_signers, ) - witness_set = self.build_witness_set() + witness_set = self.build_witness_set(True) witness_set.vkey_witnesses = [] + required_vkeys = self._build_required_vkeys() + for signing_key in set(signing_keys): + vkey_hash = signing_key.to_verification_key().hash() + if not force_skeys and vkey_hash not in required_vkeys: + logger.warning( + f"Verification key hash {vkey_hash} is not required for this tx." + ) + continue signature = signing_key.sign(tx_body.hash()) witness_set.vkey_witnesses.append( VerificationKeyWitness(signing_key.to_verification_key(), signature) ) + if len(witness_set.vkey_witnesses) == 0: + witness_set.vkey_witnesses = None + return Transaction(tx_body, witness_set, auxiliary_data=self.auxiliary_data) diff --git a/pycardano/utils.py b/pycardano/utils.py index af3a215a..7fa139f0 100644 --- a/pycardano/utils.py +++ b/pycardano/utils.py @@ -11,7 +11,7 @@ from pycardano.backend.base import ChainContext from pycardano.hash import SCRIPT_DATA_HASH_SIZE, SCRIPT_HASH_SIZE, ScriptDataHash -from pycardano.plutus import COST_MODELS, CostModels, Datum, Redeemer +from pycardano.plutus import COST_MODELS, CostModels, Datum, Redeemers from pycardano.serialization import default_encoder from pycardano.transaction import MultiAsset, TransactionOutput, Value @@ -23,14 +23,57 @@ "min_lovelace_pre_alonzo", "min_lovelace_post_alonzo", "script_data_hash", + "tiered_reference_script_fee", ] +def tiered_reference_script_fee(context: ChainContext, scripts_size: int) -> int: + """Calculate fee for reference scripts. + + Args: + context (ChainContext): A chain context. + scripts_size (int): Size of reference scripts in bytes. + + Returns: + int: Fee for reference scripts. + + Raises: + ValueError: If scripts size exceeds maximum allowed size + """ + if ( + context.protocol_param.maximum_reference_scripts_size is None + or context.protocol_param.min_fee_reference_scripts is None + ): + return 0 + + max_size = context.protocol_param.maximum_reference_scripts_size["bytes"] + if scripts_size > max_size: + raise ValueError( + f"Reference scripts size: {scripts_size} exceeds maximum allowed size ({max_size})." + ) + + total = 0.0 + if scripts_size: + b = context.protocol_param.min_fee_reference_scripts["base"] + r = math.ceil(context.protocol_param.min_fee_reference_scripts["range"]) + m = context.protocol_param.min_fee_reference_scripts["multiplier"] + + while scripts_size > r: + total += b * r + scripts_size = scripts_size - r + b = b * m + + total += b * scripts_size + + return math.ceil(total) + + def fee( context: ChainContext, length: int, exec_steps: int = 0, max_mem_unit: int = 0, + ref_script_size: int = 0, ) -> int: """Calculate fee based on the length of a transaction's CBOR bytes and script execution. @@ -38,8 +81,9 @@ def fee( context (ChainConext): A chain context. length (int): The length of CBOR bytes, which could usually be derived by `len(tx.to_cbor())`. - exec_steps (Optional[int]): Number of execution steps run by plutus scripts in the transaction. - max_mem_unit (Optional[int]): Max numer of memory units run by plutus scripts in the transaction. + exec_steps (int): Number of execution steps run by plutus scripts in the transaction. + max_mem_unit (int): Max numer of memory units run by plutus scripts in the transaction. + ref_script_size (int): Size of referenced scripts in the transaction. Return: int: Minimum acceptable transaction fee. @@ -49,14 +93,16 @@ def fee( + math.ceil(context.protocol_param.min_fee_constant) + math.ceil(exec_steps * context.protocol_param.price_step) + math.ceil(max_mem_unit * context.protocol_param.price_mem) + + tiered_reference_script_fee(context, ref_script_size) ) -def max_tx_fee(context: ChainContext) -> int: +def max_tx_fee(context: ChainContext, ref_script_size: int = 0) -> int: """Calculate the maximum possible transaction fee based on protocol parameters. Args: context (ChainContext): A chain context. + ref_script_size (int): Size of reference scripts in the transaction. Returns: int: Maximum possible tx fee in lovelace. @@ -66,6 +112,7 @@ def max_tx_fee(context: ChainContext) -> int: context.protocol_param.max_tx_size, context.protocol_param.max_tx_ex_steps, context.protocol_param.max_tx_ex_mem, + ref_script_size, ) @@ -139,7 +186,7 @@ def min_lovelace_pre_alonzo( int: Minimum required lovelace amount for this transaction output. """ if amount is None or isinstance(amount, int) or not amount.multi_asset: - return context.protocol_param.min_utxo + return context.protocol_param.min_utxo or 1_000_000 b_size = bundle_size(amount.multi_asset) utxo_entry_size = 27 @@ -186,14 +233,14 @@ def min_lovelace_post_alonzo(output: TransactionOutput, context: ChainContext) - def script_data_hash( - redeemers: List[Redeemer], + redeemers: Redeemers, datums: List[Datum], cost_models: Optional[Union[CostModels, Dict]] = None, ) -> ScriptDataHash: """Calculate plutus script data hash Args: - redeemers (List[Redeemer]): Redeemers to include. + redeemers (Redeemers): Redeemers to include. datums (List[Datum]): Datums to include. cost_models (Optional[CostModels]): Cost models. diff --git a/pycardano/witness.py b/pycardano/witness.py index 9a62923d..e47ccf3b 100644 --- a/pycardano/witness.py +++ b/pycardano/witness.py @@ -7,7 +7,19 @@ from pycardano.key import ExtendedVerificationKey, VerificationKey from pycardano.nativescript import NativeScript -from pycardano.plutus import PlutusV1Script, PlutusV2Script, RawPlutusData, Redeemer +from pycardano.plutus import ( + ExecutionUnits, + PlutusV1Script, + PlutusV2Script, + PlutusV3Script, + RawPlutusData, + Redeemer, + RedeemerKey, + RedeemerMap, + Redeemers, + RedeemerTag, + RedeemerValue, +) from pycardano.serialization import ( ArrayCBORSerializable, MapCBORSerializable, @@ -65,18 +77,22 @@ class TransactionWitnessSet(MapCBORSerializable): default=None, metadata={"optional": True, "key": 3} ) - plutus_v2_script: Optional[List[PlutusV2Script]] = field( - default=None, metadata={"optional": True, "key": 6} - ) - plutus_data: Optional[List[Any]] = field( default=None, metadata={"optional": True, "key": 4, "object_hook": list_hook(RawPlutusData)}, ) - redeemer: Optional[List[Redeemer]] = field( + redeemer: Optional[Redeemers] = field( default=None, - metadata={"optional": True, "key": 5, "object_hook": list_hook(Redeemer)}, + metadata={"optional": True, "key": 5}, + ) + + plutus_v2_script: Optional[List[PlutusV2Script]] = field( + default=None, metadata={"optional": True, "key": 6} + ) + + plutus_v3_script: Optional[List[PlutusV3Script]] = field( + default=None, metadata={"optional": True, "key": 7} ) @classmethod @@ -105,11 +121,19 @@ def _get_plutus_v2_scripts(data: Any): return [PlutusV2Script(script) for script in data] if data else None def _get_redeemers(data: Any): - return ( - [Redeemer.from_primitive(redeemer) for redeemer in data] - if data - else None - ) + if not data: + return None + if isinstance(data, dict): + redeemer_map = RedeemerMap() + for (tag, index), value in data.items(): + key = RedeemerKey(RedeemerTag(tag), index) + redeemer_value = RedeemerValue(value[0], ExecutionUnits(*value[1])) + redeemer_map[key] = redeemer_value + return redeemer_map + elif isinstance(data, list): + return [Redeemer.from_primitive(redeemer) for redeemer in data] + else: + raise ValueError(f"Unexpected redeemer data format: {type(data)}") def _get_cls(data: Any): return cls( diff --git a/pyproject.toml b/pyproject.toml index 69ae861c..922ee9bd 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -25,7 +25,7 @@ python = "^3.8.1" PyNaCl = "^1.5.0" cbor2 = "^5.4.3" typeguard = "^4.3.0" -blockfrost-python = "0.5.3" +blockfrost-python = "0.6.0" websocket-client = "^1.4.1" cose = "0.9.dev8" pprintpp = "^0.4.0" @@ -35,6 +35,9 @@ frozendict = "^2.3.8" frozenlist = "^1.3.3" cachetools = "^5.3.0" docker = "^7.1.0" +ogmios = "1.2.1" +requests = "^2.32.3" +websockets = "^13.0" [tool.poetry.dev-dependencies] Sphinx = "^5.0.0" @@ -64,7 +67,8 @@ addopts = "--doctest-modules --ignore=examples --ignore=integration-test --ignor minversion = "6.0" markers = [ "post_alonzo", - "single" + "single", + "CardanoCLI", ] diff --git a/test/pycardano/backend/test_ogmios.py b/test/pycardano/backend/test_ogmios_v5.py similarity index 97% rename from test/pycardano/backend/test_ogmios.py rename to test/pycardano/backend/test_ogmios_v5.py index 73fa2f29..ee80058a 100644 --- a/test/pycardano/backend/test_ogmios.py +++ b/test/pycardano/backend/test_ogmios_v5.py @@ -4,7 +4,7 @@ import pytest from pycardano.backend.base import GenesisParameters, ProtocolParameters -from pycardano.backend.ogmios import OgmiosChainContext +from pycardano.backend.ogmios_v5 import OgmiosV5ChainContext from pycardano.network import Network from pycardano.transaction import MultiAsset, TransactionInput @@ -112,10 +112,10 @@ def override_request(method, args): @pytest.fixture def chain_context(): with patch( - "pycardano.backend.ogmios.OgmiosChainContext._request", + "pycardano.backend.ogmios_v5.OgmiosV5ChainContext._request", side_effect=override_request, ): - context = OgmiosChainContext("", Network.TESTNET) + context = OgmiosV5ChainContext("", Network.TESTNET) context._request = override_request return context diff --git a/test/pycardano/test_metadata.py b/test/pycardano/test_metadata.py index 8a7379d3..f8d43af4 100644 --- a/test/pycardano/test_metadata.py +++ b/test/pycardano/test_metadata.py @@ -17,6 +17,7 @@ ScriptAll, ScriptPubkey, ) +from pycardano.plutus import PlutusV1Script M_PRIMITIVE = {123: {"test": b"123", 2: 3, 3: [1, 2, {(1, 2, 3): "token"}]}} @@ -56,9 +57,9 @@ def test_shelley_marry_metadata(): def test_alonzo_metadata(): script = generate_script() m = Metadata(M_PRIMITIVE) - plutus_scripts = [b"fake_script"] + plutus_scripts = [PlutusV1Script(b"fake_script")] - alonzo_m = AlonzoMetadata(m, [script], plutus_scripts) + alonzo_m = AlonzoMetadata(m, [script], plutus_v1_scripts=plutus_scripts) check_two_way_cbor(alonzo_m) @@ -73,11 +74,11 @@ def test_alonzo_metadata(): def test_auxiliary_data(): script = generate_script() - plutus_scripts = [b"fake_script"] + plutus_scripts = [PlutusV1Script(b"fake_script")] m = Metadata(M_PRIMITIVE) shelley_marry_m = ShelleyMarryMetadata(m, [script]) - alonzo_m = AlonzoMetadata(m, [script], plutus_scripts) + alonzo_m = AlonzoMetadata(m, [script], plutus_v1_scripts=plutus_scripts) check_two_way_cbor(AuxiliaryData(m)) check_two_way_cbor(AuxiliaryData(shelley_marry_m)) diff --git a/test/pycardano/test_plutus.py b/test/pycardano/test_plutus.py index b90a480d..f339a9f5 100644 --- a/test/pycardano/test_plutus.py +++ b/test/pycardano/test_plutus.py @@ -17,7 +17,10 @@ PlutusData, RawPlutusData, Redeemer, + RedeemerKey, + RedeemerMap, RedeemerTag, + RedeemerValue, Unit, id_map, plutus_script_hash, @@ -520,3 +523,64 @@ class B(PlutusData): ) assert B.from_cbor(cbor).to_cbor_hex() == cbor + + +def test_redeemer_key(): + # Test creation and equality + key1 = RedeemerKey(RedeemerTag.SPEND, 0) + key2 = RedeemerKey(RedeemerTag.SPEND, 0) + key3 = RedeemerKey(RedeemerTag.MINT, 1) + + assert key1 == key2 + assert key1 != key3 + + # Test hashing + assert hash(key1) == hash(key2) + assert hash(key1) != hash(key3) + + # Test serialization and deserialization + serialized = key1.to_primitive() + deserialized = RedeemerKey.from_primitive(serialized) + assert key1 == deserialized + + +def test_redeemer_value(): + # Test creation + data = RawPlutusData(42) + ex_units = ExecutionUnits(10, 20) + value = RedeemerValue(data, ex_units) + + assert value.data == data + assert value.ex_units == ex_units + + # Test serialization and deserialization + serialized = value.to_primitive() + deserialized = RedeemerValue.from_primitive(serialized) + assert value.data.data == deserialized.data + assert value.ex_units == deserialized.ex_units + + +def test_redeemer_map(): + # Test creation and adding items + redeemer_map = RedeemerMap() + key1 = RedeemerKey(RedeemerTag.SPEND, 0) + value1 = RedeemerValue(42, ExecutionUnits(10, 20)) + key2 = RedeemerKey(RedeemerTag.MINT, 1) + value2 = RedeemerValue(b"test", ExecutionUnits(30, 40)) + + redeemer_map[key1] = value1 + redeemer_map[key2] = value2 + + assert len(redeemer_map) == 2 + assert redeemer_map[key1] == value1 + assert redeemer_map[key2] == value2 + + # Test serialization and deserialization + serialized = redeemer_map.to_cbor() + deserialized = RedeemerMap.from_cbor(serialized) + + assert len(deserialized) == 2 + assert deserialized[key1].data == value1.data + assert deserialized[key1].ex_units == value1.ex_units + assert deserialized[key2].data == value2.data + assert deserialized[key2].ex_units == value2.ex_units diff --git a/test/pycardano/test_transaction.py b/test/pycardano/test_transaction.py index e7cc0c33..5ec6f51e 100644 --- a/test/pycardano/test_transaction.py +++ b/test/pycardano/test_transaction.py @@ -482,3 +482,94 @@ def test_out_of_bound_asset(): # Not okay only when minting with pytest.raises(InvalidDataException): tx.to_cbor_hex() + + +def test_zero_value(): + nft_output = Value( + 10000000, + MultiAsset.from_primitive( + { + bytes.fromhex( + "a39a5998f2822dfc9111e447038c3cfffa883ed1b9e357be9cd60dfe" + ): {b"MY_NFT_1": 0} + } + ), + ) + assert len(nft_output.multi_asset) == 0 + + +def test_empty_multiasset(): + nft_output = Value( + 10000000, + MultiAsset.from_primitive( + { + bytes.fromhex( + "a39a5998f2822dfc9111e447038c3cfffa883ed1b9e357be9cd60dfe" + ): {} + } + ), + ) + assert len(nft_output.multi_asset) == 0 + + +def test_add_empty(): + nft_output = Value( + 10000000, + MultiAsset.from_primitive( + { + bytes.fromhex( + "a39a5998f2822dfc9111e447038c3cfffa883ed1b9e357be9cd60dfe" + ): {b"MY_NFT_1": 100} + } + ), + ) - Value( + 5, + MultiAsset.from_primitive( + { + bytes.fromhex( + "a39a5998f2822dfc9111e447038c3cfffa883ed1b9e357be9cd60dfe" + ): {b"MY_NFT_1": 100} + } + ), + ) + assert len(nft_output.multi_asset) == 0 + + +def test_zero_value_pop(): + policy = bytes.fromhex("a39a5998f2822dfc9111e447038c3cfffa883ed1b9e357be9cd60dfe") + nft_output = Value( + 10000000, + MultiAsset.from_primitive({policy: {b"MY_NFT_1": 0, b"MY_NFT_2": 1}}), + ) + assert len(nft_output.multi_asset) == 1 + assert len(nft_output.multi_asset[ScriptHash(policy)]) == 1 + + +def test_empty_multiasset_pop(): + nft_output = Value( + 10000000, + MultiAsset.from_primitive( + { + bytes.fromhex( + "a39a5998f2822dfc9111e447038c3cfffa883ed1b9e357be9cd60dfe" + ): {}, + bytes.fromhex( + "b39a5998f2822dfc9111e447038c3cfffa883ed1b9e357be9cd60dfe" + ): {b"MY_NFT_1": 1}, + } + ), + ) + assert len(nft_output.multi_asset) == 1 + + +def test_add_empty_pop(): + policy = bytes.fromhex("a39a5998f2822dfc9111e447038c3cfffa883ed1b9e357be9cd60dfe") + nft_output = Value( + 10000000, + MultiAsset.from_primitive({policy: {b"MY_NFT_1": 100, b"MY_NFT_2": 100}}), + ) - Value( + 5, + MultiAsset.from_primitive({policy: {b"MY_NFT_1": 100}}), + ) + assert len(nft_output.multi_asset) == 1 + assert len(nft_output.multi_asset[ScriptHash(policy)]) == 1 diff --git a/test/pycardano/test_txbuilder.py b/test/pycardano/test_txbuilder.py index 373b57c5..2d0f9344 100644 --- a/test/pycardano/test_txbuilder.py +++ b/test/pycardano/test_txbuilder.py @@ -3,10 +3,12 @@ from dataclasses import replace from fractions import Fraction from test.pycardano.test_key import SK +from test.pycardano.util import check_two_way_cbor from unittest.mock import patch import pytest +from pycardano import AssetName, RedeemerKey, RedeemerMap, RedeemerValue from pycardano.address import Address from pycardano.certificate import ( PoolRegistration, @@ -25,6 +27,7 @@ POOL_KEY_HASH_SIZE, VERIFICATION_KEY_HASH_SIZE, PoolKeyHash, + TransactionId, VerificationKeyHash, ) from pycardano.key import VerificationKey @@ -39,9 +42,11 @@ PlutusData, PlutusV1Script, PlutusV2Script, + PlutusV3Script, Redeemer, RedeemerTag, plutus_script_hash, + script_hash, ) from pycardano.transaction import ( MultiAsset, @@ -53,7 +58,7 @@ ) from pycardano.txbuilder import TransactionBuilder from pycardano.utils import fee -from pycardano.witness import VerificationKeyWitness +from pycardano.witness import TransactionWitnessSet, VerificationKeyWitness def test_tx_builder(chain_context): @@ -567,11 +572,15 @@ def test_add_script_input(chain_context): ) tx_builder.add_output(TransactionOutput(receiver, 5000000)) tx_builder.build(change_address=receiver) + tx_builder.use_redeemer_map = False witness = tx_builder.build_witness_set() assert [datum] == witness.plutus_data assert [redeemer1, redeemer2] == witness.redeemer assert [plutus_script] == witness.plutus_v1_script + # Test deserialization + TransactionWitnessSet.from_cbor(witness.to_cbor_hex()) + def test_add_script_input_no_script(chain_context): tx_builder = TransactionBuilder(chain_context) @@ -595,7 +604,10 @@ def test_add_script_input_no_script(chain_context): ) tx_builder.add_output(TransactionOutput(receiver, 5000000)) tx_builder.build(change_address=receiver) - witness = tx_builder.build_witness_set() + tx_builder.use_redeemer_map = False + witness = tx_builder.build_witness_set( + remove_dup_script=True, + ) assert [datum] == witness.plutus_data assert [redeemer] == witness.redeemer assert witness.plutus_v1_script is None @@ -663,6 +675,7 @@ def test_add_script_input_find_script(chain_context): ) tx_builder.add_output(TransactionOutput(receiver, 5000000)) tx_body = tx_builder.build(change_address=receiver) + tx_builder.use_redeemer_map = False witness = tx_builder.build_witness_set() assert [datum] == witness.plutus_data assert [redeemer] == witness.redeemer @@ -702,6 +715,7 @@ def test_add_script_input_with_script_from_specified_utxo(chain_context): ) tx_builder.add_output(TransactionOutput(receiver, 5000000)) tx_body = tx_builder.build(change_address=receiver) + tx_builder.use_redeemer_map = False witness = tx_builder.build_witness_set() assert [datum] == witness.plutus_data assert [redeemer] == witness.redeemer @@ -973,6 +987,7 @@ def test_add_minting_script_from_specified_utxo(chain_context): tx_builder.add_output(TransactionOutput(receiver, 5000000)) tx_builder.mint = mint tx_body = tx_builder.build(change_address=receiver) + tx_builder.use_redeemer_map = False witness = tx_builder.build_witness_set() assert witness.plutus_data is None assert [redeemer] == witness.redeemer @@ -1102,6 +1117,7 @@ def test_add_minting_script(chain_context): ) tx_builder.add_output(TransactionOutput(receiver, Value(5000000, mint))) tx_builder.build(change_address=receiver) + tx_builder.use_redeemer_map = False witness = tx_builder.build_witness_set() assert [plutus_script] == witness.plutus_v1_script @@ -1124,6 +1140,7 @@ def test_add_minting_script_only(chain_context): ) tx_builder.add_output(TransactionOutput(receiver, Value(5000000, mint))) tx_builder.build(change_address=receiver) + tx_builder.use_redeemer_map = False witness = tx_builder.build_witness_set() assert [plutus_script] == witness.plutus_v1_script @@ -1194,6 +1211,7 @@ def test_build_and_sign(chain_context): tx = tx_builder2.build_and_sign( [SK], change_address=sender_address, + force_skeys=True, ) assert tx.transaction_witness_set.vkey_witnesses == [ @@ -1228,6 +1246,7 @@ def test_estimate_execution_unit(chain_context): ) tx_builder.add_output(TransactionOutput(receiver, 5000000)) tx_builder.build(change_address=receiver) + tx_builder.use_redeemer_map = False witness = tx_builder.build_witness_set() assert [datum] == witness.plutus_data assert [redeemer1] == witness.redeemer @@ -1737,3 +1756,289 @@ def test_tx_builder_merge_change_to_output_3(chain_context): ) tx = builder.build(change_address=address, merge_change=True) assert len(tx.outputs) == 1 + + +def test_build_witness_set_mixed_scripts(chain_context): + # Create dummy scripts + plutus_v1_script = PlutusV1Script(b"plutus v1 script") + plutus_v2_script = PlutusV2Script(b"plutus v2 script") + plutus_v3_script = PlutusV3Script(b"plutus v3 script") + + # Create a TransactionBuilder instance + builder = TransactionBuilder(chain_context) + + # Add inputs with different scripts + input_v1 = UTxO( + TransactionInput(TransactionId(32 * b"0"), 0), + TransactionOutput( + Address(script_hash(plutus_v1_script)), + Value(1000000), + script=plutus_v1_script, + ), + ) + input_v2 = UTxO( + TransactionInput(TransactionId(32 * b"0"), 1), + TransactionOutput( + Address(script_hash(plutus_v2_script)), + Value(1000000), + script=plutus_v2_script, + ), + ) + input_v3 = UTxO( + TransactionInput(TransactionId(32 * b"0"), 3), + TransactionOutput( + Address(script_hash(plutus_v3_script)), + Value(1000000), + script=plutus_v3_script, + ), + ) + builder.add_input(input_v1) + builder.add_input(input_v2) + builder.add_input(input_v3) + + # Add scripts to the builder + builder._inputs_to_scripts[input_v1] = plutus_v1_script + builder._inputs_to_scripts[input_v2] = plutus_v2_script + builder._inputs_to_scripts[input_v3] = plutus_v3_script + + # Add an additional PlutusV1Script + additional_v1_script = PlutusV1Script(b"additional v1 script") + builder._inputs_to_scripts[ + UTxO( + TransactionInput(TransactionId(32 * b"1"), 0), + TransactionOutput( + Address(script_hash(additional_v1_script)), Value(1000000) + ), + ) + ] = additional_v1_script + + # Test with remove_dup_script=True + witness_set = builder.build_witness_set(remove_dup_script=True) + assert len(witness_set.plutus_v1_script) == 1 + assert script_hash(witness_set.plutus_v1_script[0]) == script_hash( + additional_v1_script + ) + assert witness_set.plutus_v2_script is None + assert witness_set.plutus_v3_script is None + + # Test with remove_dup_script=False + witness_set = builder.build_witness_set(remove_dup_script=False) + assert len(witness_set.plutus_v1_script) == 2 + assert len(witness_set.plutus_v2_script) == 1 + assert len(witness_set.plutus_v3_script) == 1 + + +def test_add_script_input_post_chang(chain_context): + tx_builder = TransactionBuilder(chain_context) + tx_in1 = TransactionInput.from_primitive( + ["18cbe6cadecd3f89b60e08e68e5e6c7d72d730aaa1ad21431590f7e6643438ef", 0] + ) + tx_in2 = TransactionInput.from_primitive( + ["18cbe6cadecd3f89b60e08e68e5e6c7d72d730aaa1ad21431590f7e6643438ef", 1] + ) + plutus_script = PlutusV1Script(b"dummy test script") + script_hash = plutus_script_hash(plutus_script) + script_address = Address(script_hash) + datum = PlutusData() + utxo1 = UTxO( + tx_in1, TransactionOutput(script_address, 10000000, datum_hash=datum.hash()) + ) + mint = MultiAsset.from_primitive({script_hash.payload: {b"TestToken": 1}}) + UTxO( + tx_in2, + TransactionOutput( + script_address, Value(10000000, mint), datum_hash=datum.hash() + ), + ) + redeemer1 = Redeemer(PlutusData(), ExecutionUnits(1000000, 1000000)) + redeemer2 = Redeemer(PlutusData(), ExecutionUnits(5000000, 1000000)) + tx_builder.mint = mint + tx_builder.add_script_input(utxo1, plutus_script, datum, redeemer1) + tx_builder.add_minting_script(plutus_script, redeemer2) + receiver = Address.from_primitive( + "addr_test1vrm9x2zsux7va6w892g38tvchnzahvcd9tykqf3ygnmwtaqyfg52x" + ) + tx_builder.add_output(TransactionOutput(receiver, 5000000)) + tx_builder.build(change_address=receiver) + witness = tx_builder.build_witness_set() + assert [datum] == witness.plutus_data + assert [plutus_script] == witness.plutus_v1_script + + expected_redeemer_map = RedeemerMap( + { + RedeemerKey(RedeemerTag.SPEND, 0): RedeemerValue( + PlutusData(), ExecutionUnits(1000000, 1000000) + ), + RedeemerKey(RedeemerTag.MINT, 0): RedeemerValue( + PlutusData(), ExecutionUnits(5000000, 1000000) + ), + } + ) + + assert expected_redeemer_map == witness.redeemer + + +def test_transaction_witness_set_redeemers_list(chain_context): + """Test that TransactionBuilder correctly stores Redeemer list""" + tx_builder = TransactionBuilder(chain_context) + redeemer_data = [ + [0, 0, 42, [1000000, 2000000]], + [1, 1, "Hello", [3000000, 4000000]], + ] + tx_builder._redeemers = [Redeemer.from_primitive(r) for r in redeemer_data] + + assert tx_builder._redeemers is not None + assert len(tx_builder._redeemers) == 2 + assert tx_builder._redeemers[0].tag == RedeemerTag.SPEND + assert tx_builder._redeemers[0].index == 0 + assert tx_builder._redeemers[0].data == 42 + assert tx_builder._redeemers[0].ex_units == ExecutionUnits(1000000, 2000000) + assert tx_builder._redeemers[1].tag == RedeemerTag.MINT + assert tx_builder._redeemers[1].index == 1 + assert tx_builder._redeemers[1].data == "Hello" + assert tx_builder._redeemers[1].ex_units == ExecutionUnits(3000000, 4000000) + + +def test_transaction_witness_set_redeemers_dict(chain_context): + """Test that TransactionBuilder correctly stores RedeemerMap""" + tx_builder = TransactionBuilder(chain_context) + redeemer_data = { + (0, 0): [42, [1000000, 2000000]], + (1, 1): ["Hello", [3000000, 4000000]], + } + tx_builder._redeemers = RedeemerMap( + { + RedeemerKey(RedeemerTag(tag), index): RedeemerValue( + data, ExecutionUnits(*ex_units) + ) + for (tag, index), (data, ex_units) in redeemer_data.items() + } + ) + + assert tx_builder._redeemers is not None + assert isinstance(tx_builder._redeemers, RedeemerMap) + assert len(tx_builder._redeemers) == 2 + + key1 = RedeemerKey(RedeemerTag.SPEND, 0) + assert tx_builder._redeemers[key1].data == 42 + assert tx_builder._redeemers[key1].ex_units == ExecutionUnits(1000000, 2000000) + + key2 = RedeemerKey(RedeemerTag.MINT, 1) + assert tx_builder._redeemers[key2].data == "Hello" + assert tx_builder._redeemers[key2].ex_units == ExecutionUnits(3000000, 4000000) + + +def test_transaction_witness_set_redeemers_invalid_format(chain_context): + """Test that TransactionBuilder can store invalid redeemer data""" + tx_builder = TransactionBuilder(chain_context) + invalid_redeemer_data = "invalid_data" + tx_builder._redeemers = invalid_redeemer_data + assert tx_builder._redeemers == "invalid_data" + + +def test_transaction_witness_set_no_redeemers(chain_context): + """Test that build_witness_set() returns a WitnessSet with no Redeemer""" + tx_builder = TransactionBuilder(chain_context) + witness_set = tx_builder.build_witness_set() + assert witness_set.redeemer is None + + +def test_burning_all_assets_under_single_policy(chain_context): + """ + Test burning all assets under a single policy with TransactionBuilder. + + This test ensures that burning multiple assets (AssetName1, AssetName2, AssetName3, AssetName4) + under policy_id_1 removes them from the multi-asset map. + + Steps: + 1. Define assets under policy_id_1 and simulate burning 1 unit of each. + 2. Add UTXOs for the assets and burning instructions. + 3. Build the transaction and verify that all burned assets are removed. + + Args: + chain_context: The blockchain context. + + Assertions: + - AssetName1, AssetName2, AssetName3, and AssetName4 are removed after burning. + """ + tx_builder = TransactionBuilder(chain_context) + + # Create change address + sender = "addr_test1vrm9x2zsux7va6w892g38tvchnzahvcd9tykqf3ygnmwtaqyfg52x" + sender_address = Address.from_primitive(sender) + + # Create four transaction inputs + tx_in1 = TransactionInput.from_primitive( + ["a6cbe6cadecd3f89b60e08e68e5e6c7d72d730aaa1ad21431590f7e6643438ef", 0] + ) + tx_in2 = TransactionInput.from_primitive( + ["b6cbe6cadecd3f89b60e08e68e5e6c7d72d730aaa1ad21431590f7e6643438ef", 1] + ) + tx_in3 = TransactionInput.from_primitive( + ["c6cbe6cadecd3f89b60e08e68e5e6c7d72d730aaa1ad21431590f7e6643438ef", 2] + ) + tx_in4 = TransactionInput.from_primitive( + ["d6cbe6cadecd3f89b60e08e68e5e6c7d72d730aaa1ad21431590f7e6643438ef", 3] + ) + # Define a policy ID and asset names + policy_id_1 = plutus_script_hash(PlutusV1Script(b"dummy script1")) + multi_asset1 = MultiAsset.from_primitive({policy_id_1.payload: {b"AssetName1": 1}}) + multi_asset2 = MultiAsset.from_primitive({policy_id_1.payload: {b"AssetName2": 1}}) + multi_asset3 = MultiAsset.from_primitive( + { + policy_id_1.payload: {b"AssetName3": 1}, + } + ) + multi_asset4 = MultiAsset.from_primitive( + { + policy_id_1.payload: {b"AssetName4": 1}, + } + ) + + # Simulate minting and burning of assets + mint = MultiAsset.from_primitive( + { + policy_id_1.payload: { + b"AssetName1": -1, + b"AssetName2": -1, + b"AssetName3": -1, + b"AssetName4": -1, + } + } + ) + + # Set UTXO for the inputs + utxo1 = UTxO( + tx_in1, TransactionOutput(Address(policy_id_1), Value(10000000, multi_asset1)) + ) + utxo2 = UTxO( + tx_in2, TransactionOutput(Address(policy_id_1), Value(10000000, multi_asset2)) + ) + utxo3 = UTxO( + tx_in3, TransactionOutput(Address(policy_id_1), Value(10000000, multi_asset3)) + ) + utxo4 = UTxO( + tx_in4, TransactionOutput(Address(policy_id_1), Value(10000000, multi_asset4)) + ) + + # Add UTXO inputs + tx_builder.add_input(utxo1).add_input(utxo2).add_input(utxo3).add_input(utxo4) + + # Add the minting to the builder + tx_builder.mint = mint + + # Build the transaction + tx = tx_builder.build(change_address=sender_address) + + # Check that the transaction has outputs + assert tx.outputs + + # Loop through the transaction outputs to verify the multi-asset quantities + for output in tx.outputs: + multi_asset = output.amount.multi_asset + + # Ensure that AssetName1, AssetName2, AssetName3 and AssetName4 were burnt (removed) + assert AssetName(b"AssetName1") not in multi_asset.get(policy_id_1, {}) + assert AssetName(b"AssetName2") not in multi_asset.get(policy_id_1, {}) + assert AssetName(b"AssetName3") not in multi_asset.get(policy_id_1, {}) + assert AssetName(b"AseetName4") not in multi_asset.get(policy_id_1, {}) diff --git a/test/pycardano/test_util.py b/test/pycardano/test_util.py index 118c8e13..17b4f647 100644 --- a/test/pycardano/test_util.py +++ b/test/pycardano/test_util.py @@ -1,9 +1,15 @@ from test.pycardano.util import chain_context +import pytest + from pycardano.hash import SCRIPT_HASH_SIZE, ScriptDataHash from pycardano.plutus import ExecutionUnits, PlutusData, Redeemer, RedeemerTag, Unit from pycardano.transaction import Value -from pycardano.utils import min_lovelace_pre_alonzo, script_data_hash +from pycardano.utils import ( + min_lovelace_pre_alonzo, + script_data_hash, + tiered_reference_script_fee, +) def test_min_lovelace_ada_only(chain_context): @@ -82,7 +88,8 @@ def test_min_lovelace_multi_asset_6(self, chain_context): { b"1" * SCRIPT_HASH_SIZE: { - i.to_bytes(1, byteorder="big"): 1000000 * i for i in range(32) + i.to_bytes(1, byteorder="big"): 1000000 * i + for i in range(1, 33) }, b"2" * SCRIPT_HASH_SIZE: { @@ -166,3 +173,55 @@ def test_script_data_hash_redeemer_only(): assert ScriptDataHash.from_primitive( "a88fe2947b8d45d1f8b798e52174202579ecf847b8f17038c7398103df2d27b0" ) == script_data_hash(redeemers=redeemers, datums=[]) + + +class MockProtocolParam: + def __init__(self, max_size, base, range, multiplier): + self.maximum_reference_scripts_size = {"bytes": max_size} + self.min_fee_reference_scripts = { + "base": base, + "range": range, + "multiplier": multiplier, + } + + +class MockChainContext: + def __init__(self, protocol_param): + self.protocol_param = protocol_param + + +@pytest.mark.parametrize( + "max_size,base,range,multiplier,scripts_size,expected", + [ + (200 * 1024, 44, 25600, 1.2, 80 * 1024, 4489380), + ], +) +def test_tiered_reference_script_fee( + max_size, base, range, multiplier, scripts_size, expected +): + protocol_param = MockProtocolParam(max_size, base, range, multiplier) + context = MockChainContext(protocol_param) + + result = tiered_reference_script_fee(context, scripts_size) + assert result == expected + + +def test_tiered_reference_script_fee_exceeds_max_size(): + protocol_param = MockProtocolParam(1000, 10, 100, 1.1) + context = MockChainContext(protocol_param) + + with pytest.raises( + ValueError, match="Reference scripts size: 1001 exceeds maximum allowed size" + ): + tiered_reference_script_fee(context, 1001) + + +def test_tiered_reference_script_fee_no_params(): + class EmptyProtocolParam: + maximum_reference_scripts_size = None + min_fee_reference_scripts = None + + context = MockChainContext(EmptyProtocolParam()) + + result = tiered_reference_script_fee(context, 100) + assert result == 0 diff --git a/test/pycardano/util.py b/test/pycardano/util.py index 892b16eb..6b81ef74 100644 --- a/test/pycardano/util.py +++ b/test/pycardano/util.py @@ -46,6 +46,8 @@ class FixedChainContext(ChainContext): coins_per_utxo_word=34482, coins_per_utxo_byte=4310, cost_models={}, + min_fee_reference_scripts={"base": 44, "range": 25600, "multiplier": 1.2}, + maximum_reference_scripts_size={"bytes": 200_000}, ) _genesis_param = GenesisParameters(