From 721d2e9f349b2d9a22c971c07174dc93f91a5c79 Mon Sep 17 00:00:00 2001 From: huangyi Date: Wed, 3 Jul 2024 14:20:08 +0800 Subject: [PATCH 01/15] Problem: no simpler benchmark setup Solution: - most of the features of testground are not really used by us yet, so for a simple benchmark to get a TPS result, it's possible to do an alternative setup. the alternative implementation setup all the node data files in advance, then run the nodes in containers in a stateless manner, they don't need any coordinations at runtime, so we don't need those infrastructures to support the coordinations, just deploy the testplan image to the cluster like a stateless service. --- testground/benchmark/benchmark/main.py | 8 +- testground/benchmark/benchmark/peer.py | 170 ++++++---- testground/benchmark/benchmark/stateless.py | 136 ++++++++ .../benchmark/compositions/docker-compose.yml | 9 + testground/benchmark/poetry.lock | 295 ++++++++++-------- testground/benchmark/pyproject.toml | 2 + 6 files changed, 425 insertions(+), 195 deletions(-) create mode 100644 testground/benchmark/benchmark/stateless.py create mode 100644 testground/benchmark/compositions/docker-compose.yml diff --git a/testground/benchmark/benchmark/main.py b/testground/benchmark/benchmark/main.py index 49d4286608..0d21f445c6 100644 --- a/testground/benchmark/benchmark/main.py +++ b/testground/benchmark/benchmark/main.py @@ -7,12 +7,10 @@ from .cli import ChainCommand from .context import Context -from .peer import bootstrap +from .peer import CONTAINER_CRONOSD_PATH, bootstrap from .sendtx import fund_test_accounts, sendtx from .utils import export_eth_account, wait_for_block, wait_for_port -CRONOSD_PATH = "/bin/cronosd" - def influxdb_url(): return os.environ.get("INFLUXDB_URL", "http://testground-influxdb:8086") @@ -21,7 +19,7 @@ def influxdb_url(): def entrypoint(ctx: Context): ctx.init_common() - cli = ChainCommand(CRONOSD_PATH) + cli = ChainCommand(CONTAINER_CRONOSD_PATH) # build the genesis file collectively, and setup the network topology bootstrap(ctx, cli) @@ -29,7 +27,7 @@ def entrypoint(ctx: Context): # start the node logfile = Path(ctx.params.test_outputs_path) / "node.log" proc = subprocess.Popen( - [CRONOSD_PATH, "start"], + [CONTAINER_CRONOSD_PATH, "start"], stdout=open(logfile, "ab", buffering=0), ) diff --git a/testground/benchmark/benchmark/peer.py b/testground/benchmark/benchmark/peer.py index ee1113223c..7457ed8516 100644 --- a/testground/benchmark/benchmark/peer.py +++ b/testground/benchmark/benchmark/peer.py @@ -3,33 +3,79 @@ from pathlib import Path from typing import List +from .cli import ChainCommand from .context import Context from .network import get_data_ip from .topology import connect_all from .types import GenesisAccount, PeerPacket from .utils import patch_json, patch_toml +VAL_ACCOUNT = "validator" VAL_INITIAL_AMOUNT = "100000000000000000000basecro" VAL_STAKED_AMOUNT = "10000000000000000000basecro" -ACC_INITIAL_AMOUNT = "100000000000000000000basecro" +ACC_INITIAL_AMOUNT = "100000000000000000000000basecro" MEMPOOL_SIZE = 50000 +DEFAULT_DENOM = "basecro" +VALIDATOR_GROUP = "validator" +FULLNODE_GROUP = "fullnode" +CONTAINER_CRONOSD_PATH = "/bin/cronosd" def bootstrap(ctx: Context, cli) -> PeerPacket: - ip = get_data_ip(ctx.params) - cli( - "init", - f"node{ctx.global_seq}", - chain_id=ctx.params.chain_id, - default_denom="basecro", + home = Path.home() / ".cronos" + peer = init_node( + cli, + home, + get_data_ip(ctx.params), + ctx.params.chain_id, + ctx.params.test_group_id, + ctx.group_seq, + ctx.global_seq, ) - cli("keys", "add", "validator", keyring_backend="test") - cli("keys", "add", "account", keyring_backend="test") - validator_addr = cli( - "keys", "show", "validator", "--address", keyring_backend="test" + data = ctx.sync.publish_subscribe_simple( + "peers", peer.dict(), ctx.params.test_instance_count + ) + peers: List[PeerPacket] = [PeerPacket.model_validate(item) for item in data] + + if ctx.is_fullnode_leader: + # prepare genesis file and publish + genesis = gen_genesis(cli, home, peers) + ctx.sync.publish("genesis", genesis) + else: + genesis = ctx.sync.subscribe_simple("genesis", 1)[0] + (home / "config" / "genesis.json").write_text(json.dumps(genesis)) + cli("genesis", "validate", home=home) + + p2p_peers = connect_all(peer, peers) + patch_configs(home, ctx.params.test_group_id, p2p_peers) + return peer + + +def init_node( + cli: ChainCommand, + home: Path, + ip: str, + chain_id: str, + group: str, + group_seq: int, + global_seq: int, +) -> PeerPacket: + default_kwargs = { + "home": home, + "chain_id": chain_id, + "keyring_backend": "test", + } + cli( + "init", + f"{group}-{group_seq}", + default_denom=DEFAULT_DENOM, + **default_kwargs, ) - account_addr = cli("keys", "show", "account", "--address", keyring_backend="test") + cli("keys", "add", VAL_ACCOUNT, **default_kwargs) + cli("keys", "add", "account", **default_kwargs) + validator_addr = cli("keys", "show", VAL_ACCOUNT, "--address", **default_kwargs) + account_addr = cli("keys", "show", "account", "--address", **default_kwargs) accounts = [ GenesisAccount(address=validator_addr, balance=VAL_INITIAL_AMOUNT), GenesisAccount(address=account_addr, balance=ACC_INITIAL_AMOUNT), @@ -37,52 +83,50 @@ def bootstrap(ctx: Context, cli) -> PeerPacket: node_id = cli("comet", "show-node-id") peer_id = f"{node_id}@{ip}:26656" - current = PeerPacket( + peer = PeerPacket( ip=str(ip), node_id=node_id, peer_id=peer_id, accounts=accounts, ) - if ctx.is_validator: - current.gentx = gentx(cli, ctx.params.chain_id) - - data = ctx.sync.publish_subscribe_simple( - "peers", current.dict(), ctx.params.test_instance_count + if group == VALIDATOR_GROUP: + peer.gentx = gentx(cli, **default_kwargs) + + return peer + + +def gen_genesis(cli: ChainCommand, leader_home: Path, peers: List[PeerPacket]): + for peer in peers: + for account in peer.accounts: + cli( + "genesis", + "add-genesis-account", + account.address, + account.balance, + home=leader_home, + ) + collect_gen_tx(cli, peers, home=leader_home) + cli("genesis", "validate", home=leader_home) + return patch_json( + leader_home / "config" / "genesis.json", + { + "consensus.params.block.max_gas": "81500000", + "app_state.evm.params.evm_denom": "basecro", + "app_state.feemarket.params.no_base_fee": True, + }, ) - peers: List[PeerPacket] = [PeerPacket.model_validate(item) for item in data] - config_path = Path.home() / ".cronos" / "config" - if ctx.is_fullnode_leader: - # prepare genesis file and publish - for peer in peers: - for account in peer.accounts: - cli("genesis", "add-genesis-account", account.address, account.balance) - collect_gen_tx(cli, peers) - cli("genesis", "validate") - genesis = patch_json( - config_path / "genesis.json", - { - "consensus.params.block.max_gas": "81500000", - "app_state.evm.params.evm_denom": "basecro", - "app_state.feemarket.params.no_base_fee": True, - }, - ) - ctx.sync.publish("genesis", genesis) - else: - genesis = ctx.sync.subscribe_simple("genesis", 1)[0] - genesis_file = config_path / "genesis.json" - genesis_file.write_text(json.dumps(genesis)) - cli("genesis", "validate") +def patch_configs(home: Path, group: str, peers: str): # update persistent_peers and other configs in config.toml config_patch = { - "p2p.persistent_peers": connect_all(current, peers), + "p2p.persistent_peers": peers, "mempool.recheck": "false", "mempool.size": MEMPOOL_SIZE, "consensus.timeout_commit": "2s", } - if ctx.is_validator: + if group == VALIDATOR_GROUP: config_patch["tx_index.indexer"] = "null" app_patch = { @@ -92,35 +136,33 @@ def bootstrap(ctx: Context, cli) -> PeerPacket: "mempool.max-txs": MEMPOOL_SIZE, } - patch_toml(config_path / "config.toml", config_patch) - patch_toml(config_path / "app.toml", app_patch) + patch_toml(home / "config" / "config.toml", config_patch) + patch_toml(home / "config" / "app.toml", app_patch) - return current - -def gentx(cli, chain_id): +def gentx(cli, **kwargs): cli( "genesis", "add-genesis-account", - "validator", + VAL_ACCOUNT, VAL_INITIAL_AMOUNT, - keyring_backend="test", + **kwargs, ) - output = Path("gentx.json") - cli( - "genesis", - "gentx", - "validator", - VAL_STAKED_AMOUNT, - min_self_delegation=1, - chain_id=chain_id, - output_document=output, - keyring_backend="test", - ) - return json.loads(output.read_text()) + with tempfile.TemporaryDirectory() as tmp: + output = Path(tmp) / "gentx.json" + cli( + "genesis", + "gentx", + VAL_ACCOUNT, + VAL_STAKED_AMOUNT, + min_self_delegation=1, + output_document=output, + **kwargs, + ) + return json.loads(output.read_text()) -def collect_gen_tx(cli, peers): +def collect_gen_tx(cli, peers, **kwargs): """ save gentxs to file and call collect-gentxs leader node prepare genesis file and broadcast to other nodes @@ -130,4 +172,4 @@ def collect_gen_tx(cli, peers): for i, peer in enumerate(peers): if peer.gentx is not None: (tmpdir / f"gentx-{i}.json").write_text(json.dumps(peer.gentx)) - cli("genesis", "collect-gentxs", gentx_dir=str(tmpdir)) + cli("genesis", "collect-gentxs", gentx_dir=str(tmpdir), **kwargs) diff --git a/testground/benchmark/benchmark/stateless.py b/testground/benchmark/benchmark/stateless.py new file mode 100644 index 0000000000..abc17916f8 --- /dev/null +++ b/testground/benchmark/benchmark/stateless.py @@ -0,0 +1,136 @@ +import json +import os +import socket +import subprocess +from pathlib import Path +from typing import List + +import fire + +from .cli import ChainCommand +from .peer import (CONTAINER_CRONOSD_PATH, FULLNODE_GROUP, VALIDATOR_GROUP, + gen_genesis, init_node, patch_configs) +from .topology import connect_all +from .types import PeerPacket +from .utils import wait_for_block, wait_for_port + +# use cronosd on host machine +LOCAL_CRONOSD_PATH = "cronosd" +DEFAULT_CHAIN_ID = "cronos_777-1" +DEFAULT_DENOM = "basecro" +# the container must be deployed with the prefixed name +CONTAINER_PREFIX = "testplan-" + + +class CLI: + def gen(self, outdir: str, validators: int, fullnodes: int): + outdir = Path(outdir) + cli = ChainCommand(LOCAL_CRONOSD_PATH) + (outdir / VALIDATOR_GROUP).mkdir(parents=True, exist_ok=True) + (outdir / FULLNODE_GROUP).mkdir(parents=True, exist_ok=True) + + peers = [] + for i in range(validators): + print("init validator", i) + peers.append(init_node_local(cli, outdir, VALIDATOR_GROUP, i, i)) + for i in range(fullnodes): + print("init fullnode", i) + peers.append( + init_node_local(cli, outdir, FULLNODE_GROUP, i, i + validators) + ) + + print("prepare genesis") + # use a full node directory to prepare the genesis file + genesis = gen_genesis(cli, outdir / FULLNODE_GROUP / "0", peers) + + print("patch genesis") + # write genesis file and patch config files + for i in range(validators): + patch_configs_local(peers, genesis, outdir, VALIDATOR_GROUP, i, i) + for i in range(fullnodes): + patch_configs_local( + peers, genesis, outdir, FULLNODE_GROUP, i, i + validators + ) + + def run( + self, + outdir: str, + validators: int, + cronosd=CONTAINER_CRONOSD_PATH, + global_seq=None, + ): + outdir = Path(outdir) + if global_seq is None: + global_seq = node_index() + group = VALIDATOR_GROUP if global_seq < validators else FULLNODE_GROUP + group_seq = global_seq if group == VALIDATOR_GROUP else global_seq - validators + print("node role", global_seq, group, group_seq) + + home = outdir / group / str(group_seq) + + # start the node + logfile = home / "node.log" + proc = subprocess.Popen( + [cronosd, "start", "--home", str(home)], + stdout=open(logfile, "ab", buffering=0), + ) + + cli = ChainCommand(cronosd) + wait_for_port(26657) + wait_for_port(8545) + wait_for_block(cli, 1) + + proc.kill() + try: + proc.wait(5) + except subprocess.TimeoutExpired: + pass + + +def init_node_local( + cli: ChainCommand, outdir: Path, group: str, group_seq: int, global_seq: int +) -> PeerPacket: + return init_node( + cli, + outdir / group / str(group_seq), + CONTAINER_PREFIX + str(global_seq), + DEFAULT_CHAIN_ID, + group, + group_seq, + global_seq, + ) + + +def patch_configs_local( + peers: List[PeerPacket], + genesis, + outdir: Path, + group: str, + i: int, + group_seq: int, +): + home = outdir / group / str(i) + (home / "config" / "genesis.json").write_text(json.dumps(genesis)) + p2p_peers = connect_all(peers[i], peers) + patch_configs(home, group, p2p_peers) + + +def node_index() -> int: + """ + 1. try indexed job in k8s, + see: https://kubernetes.io/docs/tasks/job/indexed-parallel-processing-static/ + 2. try hostname + """ + i = os.environ.get("JOB_COMPLETION_INDEX") + if i is not None: + return int(i) + hostname = socket.gethostname() + return int(hostname.rsplit("-", 1)[-1]) + + +def main(): + fire.Fire(CLI) + + +if __name__ == "__main__": + main() diff --git a/testground/benchmark/compositions/docker-compose.yml b/testground/benchmark/compositions/docker-compose.yml new file mode 100644 index 0000000000..1ab74135d8 --- /dev/null +++ b/testground/benchmark/compositions/docker-compose.yml @@ -0,0 +1,9 @@ +version: '3' +services: + testplan: + image: ghcr.io/crypto-org-chain/cronos-testground:latest + command: stateless-testcase run /data "${VALIDATORS}" + volumes: + - benchmark-volume:/data + deploy: + replicas: 10 diff --git a/testground/benchmark/poetry.lock b/testground/benchmark/poetry.lock index 33a4ac6f68..a3b7e38b88 100644 --- a/testground/benchmark/poetry.lock +++ b/testground/benchmark/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.8.2 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.7.1 and should not be changed by hand. [[package]] name = "aiohttp" @@ -283,13 +283,13 @@ files = [ [[package]] name = "certifi" -version = "2024.2.2" +version = "2024.6.2" 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.6.2-py3-none-any.whl", hash = "sha256:ddc6c8ce995e6987e7faf5e3f1b02b302836a0e5d98ece18392cb1a36c72ad56"}, + {file = "certifi-2024.6.2.tar.gz", hash = "sha256:3cd43f1c6fa7dedc5899d69d3ad0398fd018ad1a17fba83ddaf78aa46c747516"}, ] [[package]] @@ -751,15 +751,18 @@ test = ["eth-hash[pycryptodome]", "pytest (>=7.0.0)", "pytest-xdist (>=2.4.0)"] [[package]] name = "eth-typing" -version = "4.2.3" +version = "4.3.1" description = "eth-typing: Common type annotations for ethereum python packages" optional = false python-versions = "<4,>=3.8" files = [ - {file = "eth_typing-4.2.3-py3-none-any.whl", hash = "sha256:b2df49fa89d2e85f2cc3fb1c903b0cd183d524f7a045e3db8cc720cf41adcd3d"}, - {file = "eth_typing-4.2.3.tar.gz", hash = "sha256:8ee3ae7d4136d14fcb955c34f9dbef8e52170984d4dc68c0ab0d61621eab29d8"}, + {file = "eth_typing-4.3.1-py3-none-any.whl", hash = "sha256:b4d7cee912c7779da75da4b42fa61475c1089d35a4df5081a786eaa29d5f6865"}, + {file = "eth_typing-4.3.1.tar.gz", hash = "sha256:4504559c87a9f71f4b99aa5a1e0549adaa7f192cbf8e37a295acfcddb1b5412d"}, ] +[package.dependencies] +typing-extensions = ">=4.5.0" + [package.extras] dev = ["build (>=0.9.0)", "bumpversion (>=0.5.3)", "ipython", "pre-commit (>=3.4.0)", "pytest (>=7.0.0)", "pytest-xdist (>=2.4.0)", "sphinx (>=6.0.0)", "sphinx-rtd-theme (>=1.0.0)", "towncrier (>=21,<22)", "tox (>=4.0.0)", "twine", "wheel"] docs = ["sphinx (>=6.0.0)", "sphinx-rtd-theme (>=1.0.0)", "towncrier (>=21,<22)"] @@ -787,6 +790,20 @@ dev = ["build (>=0.9.0)", "bumpversion (>=0.5.3)", "eth-hash[pycryptodome]", "hy docs = ["sphinx (>=6.0.0)", "sphinx-autobuild (>=2021.3.14)", "sphinx-rtd-theme (>=1.0.0)", "towncrier (>=21,<22)"] test = ["hypothesis (>=4.43.0)", "mypy (==1.5.1)", "pytest (>=7.0.0)", "pytest-xdist (>=2.4.0)"] +[[package]] +name = "fire" +version = "0.6.0" +description = "A library for automatically generating command line interfaces." +optional = false +python-versions = "*" +files = [ + {file = "fire-0.6.0.tar.gz", hash = "sha256:54ec5b996ecdd3c0309c800324a0703d6da512241bc73b553db959d98de0aa66"}, +] + +[package.dependencies] +six = "*" +termcolor = "*" + [[package]] name = "frozenlist" version = "1.4.1" @@ -903,13 +920,13 @@ files = [ [[package]] name = "influxdb-client" -version = "1.43.0" +version = "1.44.0" description = "InfluxDB 2.0 Python client library" optional = false python-versions = ">=3.7" files = [ - {file = "influxdb_client-1.43.0-py3-none-any.whl", hash = "sha256:f079e63018f521024118bc0141b6403c65506711e2e6e93500f8e69f1675dc38"}, - {file = "influxdb_client-1.43.0.tar.gz", hash = "sha256:ae2614d891baed52c0ae8f6194a04ee5b1c6422f6061318a3639fe63b7671b25"}, + {file = "influxdb_client-1.44.0-py3-none-any.whl", hash = "sha256:e4c1ac9c9925c4693d63e988e22f65d2ddc1867f8910813b7f4721633175f2a0"}, + {file = "influxdb_client-1.44.0.tar.gz", hash = "sha256:da9bc0cc49de4a0ac844d833c1efa65227ec5a2254e63cdbe07b5d532c0c37f8"}, ] [package.dependencies] @@ -1205,13 +1222,13 @@ files = [ [[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]] @@ -1245,22 +1262,22 @@ testing = ["pytest", "pytest-benchmark"] [[package]] name = "protobuf" -version = "5.27.0" +version = "5.27.2" description = "" optional = false python-versions = ">=3.8" files = [ - {file = "protobuf-5.27.0-cp310-abi3-win32.whl", hash = "sha256:2f83bf341d925650d550b8932b71763321d782529ac0eaf278f5242f513cc04e"}, - {file = "protobuf-5.27.0-cp310-abi3-win_amd64.whl", hash = "sha256:b276e3f477ea1eebff3c2e1515136cfcff5ac14519c45f9b4aa2f6a87ea627c4"}, - {file = "protobuf-5.27.0-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:744489f77c29174328d32f8921566fb0f7080a2f064c5137b9d6f4b790f9e0c1"}, - {file = "protobuf-5.27.0-cp38-abi3-manylinux2014_aarch64.whl", hash = "sha256:f51f33d305e18646f03acfdb343aac15b8115235af98bc9f844bf9446573827b"}, - {file = "protobuf-5.27.0-cp38-abi3-manylinux2014_x86_64.whl", hash = "sha256:56937f97ae0dcf4e220ff2abb1456c51a334144c9960b23597f044ce99c29c89"}, - {file = "protobuf-5.27.0-cp38-cp38-win32.whl", hash = "sha256:a17f4d664ea868102feaa30a674542255f9f4bf835d943d588440d1f49a3ed15"}, - {file = "protobuf-5.27.0-cp38-cp38-win_amd64.whl", hash = "sha256:aabbbcf794fbb4c692ff14ce06780a66d04758435717107c387f12fb477bf0d8"}, - {file = "protobuf-5.27.0-cp39-cp39-win32.whl", hash = "sha256:587be23f1212da7a14a6c65fd61995f8ef35779d4aea9e36aad81f5f3b80aec5"}, - {file = "protobuf-5.27.0-cp39-cp39-win_amd64.whl", hash = "sha256:7cb65fc8fba680b27cf7a07678084c6e68ee13cab7cace734954c25a43da6d0f"}, - {file = "protobuf-5.27.0-py3-none-any.whl", hash = "sha256:673ad60f1536b394b4fa0bcd3146a4130fcad85bfe3b60eaa86d6a0ace0fa374"}, - {file = "protobuf-5.27.0.tar.gz", hash = "sha256:07f2b9a15255e3cf3f137d884af7972407b556a7a220912b252f26dc3121e6bf"}, + {file = "protobuf-5.27.2-cp310-abi3-win32.whl", hash = "sha256:354d84fac2b0d76062e9b3221f4abbbacdfd2a4d8af36bab0474f3a0bb30ab38"}, + {file = "protobuf-5.27.2-cp310-abi3-win_amd64.whl", hash = "sha256:0e341109c609749d501986b835f667c6e1e24531096cff9d34ae411595e26505"}, + {file = "protobuf-5.27.2-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:a109916aaac42bff84702fb5187f3edadbc7c97fc2c99c5ff81dd15dcce0d1e5"}, + {file = "protobuf-5.27.2-cp38-abi3-manylinux2014_aarch64.whl", hash = "sha256:176c12b1f1c880bf7a76d9f7c75822b6a2bc3db2d28baa4d300e8ce4cde7409b"}, + {file = "protobuf-5.27.2-cp38-abi3-manylinux2014_x86_64.whl", hash = "sha256:b848dbe1d57ed7c191dfc4ea64b8b004a3f9ece4bf4d0d80a367b76df20bf36e"}, + {file = "protobuf-5.27.2-cp38-cp38-win32.whl", hash = "sha256:4fadd8d83e1992eed0248bc50a4a6361dc31bcccc84388c54c86e530b7f58863"}, + {file = "protobuf-5.27.2-cp38-cp38-win_amd64.whl", hash = "sha256:610e700f02469c4a997e58e328cac6f305f649826853813177e6290416e846c6"}, + {file = "protobuf-5.27.2-cp39-cp39-win32.whl", hash = "sha256:9e8f199bf7f97bd7ecebffcae45ebf9527603549b2b562df0fbc6d4d688f14ca"}, + {file = "protobuf-5.27.2-cp39-cp39-win_amd64.whl", hash = "sha256:7fc3add9e6003e026da5fc9e59b131b8f22b428b991ccd53e2af8071687b4fce"}, + {file = "protobuf-5.27.2-py3-none-any.whl", hash = "sha256:54330f07e4949d09614707c48b06d1a22f8ffb5763c159efd5c0928326a91470"}, + {file = "protobuf-5.27.2.tar.gz", hash = "sha256:f3ecdef226b9af856075f28227ff2c90ce3a594d092c39bee5513573f25e2714"}, ] [[package]] @@ -1306,109 +1323,121 @@ files = [ [[package]] name = "pydantic" -version = "2.7.2" +version = "2.8.0" description = "Data validation using Python type hints" optional = false python-versions = ">=3.8" files = [ - {file = "pydantic-2.7.2-py3-none-any.whl", hash = "sha256:834ab954175f94e6e68258537dc49402c4a5e9d0409b9f1b86b7e934a8372de7"}, - {file = "pydantic-2.7.2.tar.gz", hash = "sha256:71b2945998f9c9b7919a45bde9a50397b289937d215ae141c1d0903ba7149fd7"}, + {file = "pydantic-2.8.0-py3-none-any.whl", hash = "sha256:ead4f3a1e92386a734ca1411cb25d94147cf8778ed5be6b56749047676d6364e"}, + {file = "pydantic-2.8.0.tar.gz", hash = "sha256:d970ffb9d030b710795878940bd0489842c638e7252fc4a19c3ae2f7da4d6141"}, ] [package.dependencies] annotated-types = ">=0.4.0" -pydantic-core = "2.18.3" -typing-extensions = ">=4.6.1" +pydantic-core = "2.20.0" +typing-extensions = [ + {version = ">=4.12.2", markers = "python_version >= \"3.13\""}, + {version = ">=4.6.1", markers = "python_version < \"3.13\""}, +] [package.extras] email = ["email-validator (>=2.0.0)"] [[package]] name = "pydantic-core" -version = "2.18.3" +version = "2.20.0" description = "Core functionality for Pydantic validation and serialization" optional = false python-versions = ">=3.8" files = [ - {file = "pydantic_core-2.18.3-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:744697428fcdec6be5670460b578161d1ffe34743a5c15656be7ea82b008197c"}, - {file = "pydantic_core-2.18.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:37b40c05ced1ba4218b14986fe6f283d22e1ae2ff4c8e28881a70fb81fbfcda7"}, - {file = "pydantic_core-2.18.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:544a9a75622357076efb6b311983ff190fbfb3c12fc3a853122b34d3d358126c"}, - {file = "pydantic_core-2.18.3-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e2e253af04ceaebde8eb201eb3f3e3e7e390f2d275a88300d6a1959d710539e2"}, - {file = "pydantic_core-2.18.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:855ec66589c68aa367d989da5c4755bb74ee92ccad4fdb6af942c3612c067e34"}, - {file = "pydantic_core-2.18.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3d3e42bb54e7e9d72c13ce112e02eb1b3b55681ee948d748842171201a03a98a"}, - {file = "pydantic_core-2.18.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c6ac9ffccc9d2e69d9fba841441d4259cb668ac180e51b30d3632cd7abca2b9b"}, - {file = "pydantic_core-2.18.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c56eca1686539fa0c9bda992e7bd6a37583f20083c37590413381acfc5f192d6"}, - {file = "pydantic_core-2.18.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:17954d784bf8abfc0ec2a633108207ebc4fa2df1a0e4c0c3ccbaa9bb01d2c426"}, - {file = "pydantic_core-2.18.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:98ed737567d8f2ecd54f7c8d4f8572ca7c7921ede93a2e52939416170d357812"}, - {file = "pydantic_core-2.18.3-cp310-none-win32.whl", hash = "sha256:9f9e04afebd3ed8c15d67a564ed0a34b54e52136c6d40d14c5547b238390e779"}, - {file = "pydantic_core-2.18.3-cp310-none-win_amd64.whl", hash = "sha256:45e4ffbae34f7ae30d0047697e724e534a7ec0a82ef9994b7913a412c21462a0"}, - {file = "pydantic_core-2.18.3-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:b9ebe8231726c49518b16b237b9fe0d7d361dd221302af511a83d4ada01183ab"}, - {file = "pydantic_core-2.18.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:b8e20e15d18bf7dbb453be78a2d858f946f5cdf06c5072453dace00ab652e2b2"}, - {file = "pydantic_core-2.18.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c0d9ff283cd3459fa0bf9b0256a2b6f01ac1ff9ffb034e24457b9035f75587cb"}, - {file = "pydantic_core-2.18.3-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2f7ef5f0ebb77ba24c9970da18b771711edc5feaf00c10b18461e0f5f5949231"}, - {file = "pydantic_core-2.18.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:73038d66614d2e5cde30435b5afdced2b473b4c77d4ca3a8624dd3e41a9c19be"}, - {file = "pydantic_core-2.18.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6afd5c867a74c4d314c557b5ea9520183fadfbd1df4c2d6e09fd0d990ce412cd"}, - {file = "pydantic_core-2.18.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bd7df92f28d351bb9f12470f4c533cf03d1b52ec5a6e5c58c65b183055a60106"}, - {file = "pydantic_core-2.18.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:80aea0ffeb1049336043d07799eace1c9602519fb3192916ff525b0287b2b1e4"}, - {file = "pydantic_core-2.18.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:aaee40f25bba38132e655ffa3d1998a6d576ba7cf81deff8bfa189fb43fd2bbe"}, - {file = "pydantic_core-2.18.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:9128089da8f4fe73f7a91973895ebf2502539d627891a14034e45fb9e707e26d"}, - {file = "pydantic_core-2.18.3-cp311-none-win32.whl", hash = "sha256:fec02527e1e03257aa25b1a4dcbe697b40a22f1229f5d026503e8b7ff6d2eda7"}, - {file = "pydantic_core-2.18.3-cp311-none-win_amd64.whl", hash = "sha256:58ff8631dbab6c7c982e6425da8347108449321f61fe427c52ddfadd66642af7"}, - {file = "pydantic_core-2.18.3-cp311-none-win_arm64.whl", hash = "sha256:3fc1c7f67f34c6c2ef9c213e0f2a351797cda98249d9ca56a70ce4ebcaba45f4"}, - {file = "pydantic_core-2.18.3-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:f0928cde2ae416a2d1ebe6dee324709c6f73e93494d8c7aea92df99aab1fc40f"}, - {file = "pydantic_core-2.18.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0bee9bb305a562f8b9271855afb6ce00223f545de3d68560b3c1649c7c5295e9"}, - {file = "pydantic_core-2.18.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e862823be114387257dacbfa7d78547165a85d7add33b446ca4f4fae92c7ff5c"}, - {file = "pydantic_core-2.18.3-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:6a36f78674cbddc165abab0df961b5f96b14461d05feec5e1f78da58808b97e7"}, - {file = "pydantic_core-2.18.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ba905d184f62e7ddbb7a5a751d8a5c805463511c7b08d1aca4a3e8c11f2e5048"}, - {file = "pydantic_core-2.18.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7fdd362f6a586e681ff86550b2379e532fee63c52def1c666887956748eaa326"}, - {file = "pydantic_core-2.18.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:24b214b7ee3bd3b865e963dbed0f8bc5375f49449d70e8d407b567af3222aae4"}, - {file = "pydantic_core-2.18.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:691018785779766127f531674fa82bb368df5b36b461622b12e176c18e119022"}, - {file = "pydantic_core-2.18.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:60e4c625e6f7155d7d0dcac151edf5858102bc61bf959d04469ca6ee4e8381bd"}, - {file = "pydantic_core-2.18.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:a4e651e47d981c1b701dcc74ab8fec5a60a5b004650416b4abbef13db23bc7be"}, - {file = "pydantic_core-2.18.3-cp312-none-win32.whl", hash = "sha256:ffecbb5edb7f5ffae13599aec33b735e9e4c7676ca1633c60f2c606beb17efc5"}, - {file = "pydantic_core-2.18.3-cp312-none-win_amd64.whl", hash = "sha256:2c8333f6e934733483c7eddffdb094c143b9463d2af7e6bd85ebcb2d4a1b82c6"}, - {file = "pydantic_core-2.18.3-cp312-none-win_arm64.whl", hash = "sha256:7a20dded653e516a4655f4c98e97ccafb13753987434fe7cf044aa25f5b7d417"}, - {file = "pydantic_core-2.18.3-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:eecf63195be644b0396f972c82598cd15693550f0ff236dcf7ab92e2eb6d3522"}, - {file = "pydantic_core-2.18.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:2c44efdd3b6125419c28821590d7ec891c9cb0dff33a7a78d9d5c8b6f66b9702"}, - {file = "pydantic_core-2.18.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6e59fca51ffbdd1638b3856779342ed69bcecb8484c1d4b8bdb237d0eb5a45e2"}, - {file = "pydantic_core-2.18.3-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:70cf099197d6b98953468461d753563b28e73cf1eade2ffe069675d2657ed1d5"}, - {file = "pydantic_core-2.18.3-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:63081a49dddc6124754b32a3774331467bfc3d2bd5ff8f10df36a95602560361"}, - {file = "pydantic_core-2.18.3-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:370059b7883485c9edb9655355ff46d912f4b03b009d929220d9294c7fd9fd60"}, - {file = "pydantic_core-2.18.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5a64faeedfd8254f05f5cf6fc755023a7e1606af3959cfc1a9285744cc711044"}, - {file = "pydantic_core-2.18.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:19d2e725de0f90d8671f89e420d36c3dd97639b98145e42fcc0e1f6d492a46dc"}, - {file = "pydantic_core-2.18.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:67bc078025d70ec5aefe6200ef094576c9d86bd36982df1301c758a9fff7d7f4"}, - {file = "pydantic_core-2.18.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:adf952c3f4100e203cbaf8e0c907c835d3e28f9041474e52b651761dc248a3c0"}, - {file = "pydantic_core-2.18.3-cp38-none-win32.whl", hash = "sha256:9a46795b1f3beb167eaee91736d5d17ac3a994bf2215a996aed825a45f897558"}, - {file = "pydantic_core-2.18.3-cp38-none-win_amd64.whl", hash = "sha256:200ad4e3133cb99ed82342a101a5abf3d924722e71cd581cc113fe828f727fbc"}, - {file = "pydantic_core-2.18.3-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:304378b7bf92206036c8ddd83a2ba7b7d1a5b425acafff637172a3aa72ad7083"}, - {file = "pydantic_core-2.18.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c826870b277143e701c9ccf34ebc33ddb4d072612683a044e7cce2d52f6c3fef"}, - {file = "pydantic_core-2.18.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e201935d282707394f3668380e41ccf25b5794d1b131cdd96b07f615a33ca4b1"}, - {file = "pydantic_core-2.18.3-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5560dda746c44b48bf82b3d191d74fe8efc5686a9ef18e69bdabccbbb9ad9442"}, - {file = "pydantic_core-2.18.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6b32c2a1f8032570842257e4c19288eba9a2bba4712af542327de9a1204faff8"}, - {file = "pydantic_core-2.18.3-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:929c24e9dea3990bc8bcd27c5f2d3916c0c86f5511d2caa69e0d5290115344a9"}, - {file = "pydantic_core-2.18.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e1a8376fef60790152564b0eab376b3e23dd6e54f29d84aad46f7b264ecca943"}, - {file = "pydantic_core-2.18.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:dccf3ef1400390ddd1fb55bf0632209d39140552d068ee5ac45553b556780e06"}, - {file = "pydantic_core-2.18.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:41dbdcb0c7252b58fa931fec47937edb422c9cb22528f41cb8963665c372caf6"}, - {file = "pydantic_core-2.18.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:666e45cf071669fde468886654742fa10b0e74cd0fa0430a46ba6056b24fb0af"}, - {file = "pydantic_core-2.18.3-cp39-none-win32.whl", hash = "sha256:f9c08cabff68704a1b4667d33f534d544b8a07b8e5d039c37067fceb18789e78"}, - {file = "pydantic_core-2.18.3-cp39-none-win_amd64.whl", hash = "sha256:4afa5f5973e8572b5c0dcb4e2d4fda7890e7cd63329bd5cc3263a25c92ef0026"}, - {file = "pydantic_core-2.18.3-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:77319771a026f7c7d29c6ebc623de889e9563b7087911b46fd06c044a12aa5e9"}, - {file = "pydantic_core-2.18.3-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:df11fa992e9f576473038510d66dd305bcd51d7dd508c163a8c8fe148454e059"}, - {file = "pydantic_core-2.18.3-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d531076bdfb65af593326ffd567e6ab3da145020dafb9187a1d131064a55f97c"}, - {file = "pydantic_core-2.18.3-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d33ce258e4e6e6038f2b9e8b8a631d17d017567db43483314993b3ca345dcbbb"}, - {file = "pydantic_core-2.18.3-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1f9cd7f5635b719939019be9bda47ecb56e165e51dd26c9a217a433e3d0d59a9"}, - {file = "pydantic_core-2.18.3-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:cd4a032bb65cc132cae1fe3e52877daecc2097965cd3914e44fbd12b00dae7c5"}, - {file = "pydantic_core-2.18.3-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:82f2718430098bcdf60402136c845e4126a189959d103900ebabb6774a5d9fdb"}, - {file = "pydantic_core-2.18.3-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:c0037a92cf0c580ed14e10953cdd26528e8796307bb8bb312dc65f71547df04d"}, - {file = "pydantic_core-2.18.3-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:b95a0972fac2b1ff3c94629fc9081b16371dad870959f1408cc33b2f78ad347a"}, - {file = "pydantic_core-2.18.3-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:a62e437d687cc148381bdd5f51e3e81f5b20a735c55f690c5be94e05da2b0d5c"}, - {file = "pydantic_core-2.18.3-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b367a73a414bbb08507da102dc2cde0fa7afe57d09b3240ce82a16d608a7679c"}, - {file = "pydantic_core-2.18.3-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0ecce4b2360aa3f008da3327d652e74a0e743908eac306198b47e1c58b03dd2b"}, - {file = "pydantic_core-2.18.3-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:bd4435b8d83f0c9561a2a9585b1de78f1abb17cb0cef5f39bf6a4b47d19bafe3"}, - {file = "pydantic_core-2.18.3-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:616221a6d473c5b9aa83fa8982745441f6a4a62a66436be9445c65f241b86c94"}, - {file = "pydantic_core-2.18.3-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:7e6382ce89a92bc1d0c0c5edd51e931432202b9080dc921d8d003e616402efd1"}, - {file = "pydantic_core-2.18.3-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:ff58f379345603d940e461eae474b6bbb6dab66ed9a851ecd3cb3709bf4dcf6a"}, - {file = "pydantic_core-2.18.3.tar.gz", hash = "sha256:432e999088d85c8f36b9a3f769a8e2b57aabd817bbb729a90d1fe7f18f6f1f39"}, + {file = "pydantic_core-2.20.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:e9dcd7fb34f7bfb239b5fa420033642fff0ad676b765559c3737b91f664d4fa9"}, + {file = "pydantic_core-2.20.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:649a764d9b0da29816889424697b2a3746963ad36d3e0968784ceed6e40c6355"}, + {file = "pydantic_core-2.20.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7701df088d0b05f3460f7ba15aec81ac8b0fb5690367dfd072a6c38cf5b7fdb5"}, + {file = "pydantic_core-2.20.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ab760f17c3e792225cdaef31ca23c0aea45c14ce80d8eff62503f86a5ab76bff"}, + {file = "pydantic_core-2.20.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cb1ad5b4d73cde784cf64580166568074f5ccd2548d765e690546cff3d80937d"}, + {file = "pydantic_core-2.20.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b81ec2efc04fc1dbf400647d4357d64fb25543bae38d2d19787d69360aad21c9"}, + {file = "pydantic_core-2.20.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c4a9732a5cad764ba37f3aa873dccb41b584f69c347a57323eda0930deec8e10"}, + {file = "pydantic_core-2.20.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:6dc85b9e10cc21d9c1055f15684f76fa4facadddcb6cd63abab702eb93c98943"}, + {file = "pydantic_core-2.20.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:21d9f7e24f63fdc7118e6cc49defaab8c1d27570782f7e5256169d77498cf7c7"}, + {file = "pydantic_core-2.20.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:8b315685832ab9287e6124b5d74fc12dda31e6421d7f6b08525791452844bc2d"}, + {file = "pydantic_core-2.20.0-cp310-none-win32.whl", hash = "sha256:c3dc8ec8b87c7ad534c75b8855168a08a7036fdb9deeeed5705ba9410721c84d"}, + {file = "pydantic_core-2.20.0-cp310-none-win_amd64.whl", hash = "sha256:85770b4b37bb36ef93a6122601795231225641003e0318d23c6233c59b424279"}, + {file = "pydantic_core-2.20.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:58e251bb5a5998f7226dc90b0b753eeffa720bd66664eba51927c2a7a2d5f32c"}, + {file = "pydantic_core-2.20.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:78d584caac52c24240ef9ecd75de64c760bbd0e20dbf6973631815e3ef16ef8b"}, + {file = "pydantic_core-2.20.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5084ec9721f82bef5ff7c4d1ee65e1626783abb585f8c0993833490b63fe1792"}, + {file = "pydantic_core-2.20.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:6d0f52684868db7c218437d260e14d37948b094493f2646f22d3dda7229bbe3f"}, + {file = "pydantic_core-2.20.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1def125d59a87fe451212a72ab9ed34c118ff771e5473fef4f2f95d8ede26d75"}, + {file = "pydantic_core-2.20.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b34480fd6778ab356abf1e9086a4ced95002a1e195e8d2fd182b0def9d944d11"}, + {file = "pydantic_core-2.20.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d42669d319db366cb567c3b444f43caa7ffb779bf9530692c6f244fc635a41eb"}, + {file = "pydantic_core-2.20.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:53b06aea7a48919a254b32107647be9128c066aaa6ee6d5d08222325f25ef175"}, + {file = "pydantic_core-2.20.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:1f038156b696a1c39d763b2080aeefa87ddb4162c10aa9fabfefffc3dd8180fa"}, + {file = "pydantic_core-2.20.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:3f0f3a4a23717280a5ee3ac4fb1f81d6fde604c9ec5100f7f6f987716bb8c137"}, + {file = "pydantic_core-2.20.0-cp311-none-win32.whl", hash = "sha256:316fe7c3fec017affd916a0c83d6f1ec697cbbbdf1124769fa73328e7907cc2e"}, + {file = "pydantic_core-2.20.0-cp311-none-win_amd64.whl", hash = "sha256:2d06a7fa437f93782e3f32d739c3ec189f82fca74336c08255f9e20cea1ed378"}, + {file = "pydantic_core-2.20.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:d6f8c49657f3eb7720ed4c9b26624063da14937fc94d1812f1e04a2204db3e17"}, + {file = "pydantic_core-2.20.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ad1bd2f377f56fec11d5cfd0977c30061cd19f4fa199bf138b200ec0d5e27eeb"}, + {file = "pydantic_core-2.20.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ed741183719a5271f97d93bbcc45ed64619fa38068aaa6e90027d1d17e30dc8d"}, + {file = "pydantic_core-2.20.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d82e5ed3a05f2dcb89c6ead2fd0dbff7ac09bc02c1b4028ece2d3a3854d049ce"}, + {file = "pydantic_core-2.20.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b2ba34a099576234671f2e4274e5bc6813b22e28778c216d680eabd0db3f7dad"}, + {file = "pydantic_core-2.20.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:879ae6bb08a063b3e1b7ac8c860096d8fd6b48dd9b2690b7f2738b8c835e744b"}, + {file = "pydantic_core-2.20.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0b0eefc7633a04c0694340aad91fbfd1986fe1a1e0c63a22793ba40a18fcbdc8"}, + {file = "pydantic_core-2.20.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:73deadd6fd8a23e2f40b412b3ac617a112143c8989a4fe265050fd91ba5c0608"}, + {file = "pydantic_core-2.20.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:35681445dc85446fb105943d81ae7569aa7e89de80d1ca4ac3229e05c311bdb1"}, + {file = "pydantic_core-2.20.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:0f6dd3612a3b9f91f2e63924ea18a4476656c6d01843ca20a4c09e00422195af"}, + {file = "pydantic_core-2.20.0-cp312-none-win32.whl", hash = "sha256:7e37b6bb6e90c2b8412b06373c6978d9d81e7199a40e24a6ef480e8acdeaf918"}, + {file = "pydantic_core-2.20.0-cp312-none-win_amd64.whl", hash = "sha256:7d4df13d1c55e84351fab51383520b84f490740a9f1fec905362aa64590b7a5d"}, + {file = "pydantic_core-2.20.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:d43e7ab3b65e4dc35a7612cfff7b0fd62dce5bc11a7cd198310b57f39847fd6c"}, + {file = "pydantic_core-2.20.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7b6a24d7b5893392f2b8e3b7a0031ae3b14c6c1942a4615f0d8794fdeeefb08b"}, + {file = "pydantic_core-2.20.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b2f13c3e955a087c3ec86f97661d9f72a76e221281b2262956af381224cfc243"}, + {file = "pydantic_core-2.20.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:72432fd6e868c8d0a6849869e004b8bcae233a3c56383954c228316694920b38"}, + {file = "pydantic_core-2.20.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d70a8ff2d4953afb4cbe6211f17268ad29c0b47e73d3372f40e7775904bc28fc"}, + {file = "pydantic_core-2.20.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8e49524917b8d3c2f42cd0d2df61178e08e50f5f029f9af1f402b3ee64574392"}, + {file = "pydantic_core-2.20.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a4f0f71653b1c1bad0350bc0b4cc057ab87b438ff18fa6392533811ebd01439c"}, + {file = "pydantic_core-2.20.0-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:16197e6f4fdecb9892ed2436e507e44f0a1aa2cff3b9306d1c879ea2f9200997"}, + {file = "pydantic_core-2.20.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:763602504bf640b3ded3bba3f8ed8a1cc2fc6a87b8d55c1c5689f428c49c947e"}, + {file = "pydantic_core-2.20.0-cp313-none-win32.whl", hash = "sha256:a3f243f318bd9523277fa123b3163f4c005a3e8619d4b867064de02f287a564d"}, + {file = "pydantic_core-2.20.0-cp313-none-win_amd64.whl", hash = "sha256:03aceaf6a5adaad3bec2233edc5a7905026553916615888e53154807e404545c"}, + {file = "pydantic_core-2.20.0-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:d6f2d8b8da1f03f577243b07bbdd3412eee3d37d1f2fd71d1513cbc76a8c1239"}, + {file = "pydantic_core-2.20.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:a272785a226869416c6b3c1b7e450506152d3844207331f02f27173562c917e0"}, + {file = "pydantic_core-2.20.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:efbb412d55a4ffe73963fed95c09ccb83647ec63b711c4b3752be10a56f0090b"}, + {file = "pydantic_core-2.20.0-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:1e4f46189d8740561b43655263a41aac75ff0388febcb2c9ec4f1b60a0ec12f3"}, + {file = "pydantic_core-2.20.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:87d3df115f4a3c8c5e4d5acf067d399c6466d7e604fc9ee9acbe6f0c88a0c3cf"}, + {file = "pydantic_core-2.20.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a340d2bdebe819d08f605e9705ed551c3feb97e4fd71822d7147c1e4bdbb9508"}, + {file = "pydantic_core-2.20.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:616b9c2f882393d422ba11b40e72382fe975e806ad693095e9a3b67c59ea6150"}, + {file = "pydantic_core-2.20.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:25c46bb2ff6084859bbcfdf4f1a63004b98e88b6d04053e8bf324e115398e9e7"}, + {file = "pydantic_core-2.20.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:23425eccef8f2c342f78d3a238c824623836c6c874d93c726673dbf7e56c78c0"}, + {file = "pydantic_core-2.20.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:52527e8f223ba29608d999d65b204676398009725007c9336651c2ec2d93cffc"}, + {file = "pydantic_core-2.20.0-cp38-none-win32.whl", hash = "sha256:1c3c5b7f70dd19a6845292b0775295ea81c61540f68671ae06bfe4421b3222c2"}, + {file = "pydantic_core-2.20.0-cp38-none-win_amd64.whl", hash = "sha256:8093473d7b9e908af1cef30025609afc8f5fd2a16ff07f97440fd911421e4432"}, + {file = "pydantic_core-2.20.0-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:ee7785938e407418795e4399b2bf5b5f3cf6cf728077a7f26973220d58d885cf"}, + {file = "pydantic_core-2.20.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:0e75794883d635071cf6b4ed2a5d7a1e50672ab7a051454c76446ef1ebcdcc91"}, + {file = "pydantic_core-2.20.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:344e352c96e53b4f56b53d24728217c69399b8129c16789f70236083c6ceb2ac"}, + {file = "pydantic_core-2.20.0-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:978d4123ad1e605daf1ba5e01d4f235bcf7b6e340ef07e7122e8e9cfe3eb61ab"}, + {file = "pydantic_core-2.20.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3c05eaf6c863781eb834ab41f5963604ab92855822a2062897958089d1335dad"}, + {file = "pydantic_core-2.20.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bc7e43b4a528ffca8c9151b6a2ca34482c2fdc05e6aa24a84b7f475c896fc51d"}, + {file = "pydantic_core-2.20.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:658287a29351166510ebbe0a75c373600cc4367a3d9337b964dada8d38bcc0f4"}, + {file = "pydantic_core-2.20.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1dacf660d6de692fe351e8c806e7efccf09ee5184865893afbe8e59be4920b4a"}, + {file = "pydantic_core-2.20.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:3e147fc6e27b9a487320d78515c5f29798b539179f7777018cedf51b7749e4f4"}, + {file = "pydantic_core-2.20.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:c867230d715a3dd1d962c8d9bef0d3168994ed663e21bf748b6e3a529a129aab"}, + {file = "pydantic_core-2.20.0-cp39-none-win32.whl", hash = "sha256:22b813baf0dbf612752d8143a2dbf8e33ccb850656b7850e009bad2e101fc377"}, + {file = "pydantic_core-2.20.0-cp39-none-win_amd64.whl", hash = "sha256:3a7235b46c1bbe201f09b6f0f5e6c36b16bad3d0532a10493742f91fbdc8035f"}, + {file = "pydantic_core-2.20.0-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:cafde15a6f7feaec2f570646e2ffc5b73412295d29134a29067e70740ec6ee20"}, + {file = "pydantic_core-2.20.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:2aec8eeea0b08fd6bc2213d8e86811a07491849fd3d79955b62d83e32fa2ad5f"}, + {file = "pydantic_core-2.20.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:840200827984f1c4e114008abc2f5ede362d6e11ed0b5931681884dd41852ff1"}, + {file = "pydantic_core-2.20.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f8ea1d8b7df522e5ced34993c423c3bf3735c53df8b2a15688a2f03a7d678800"}, + {file = "pydantic_core-2.20.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d5b8376a867047bf08910573deb95d3c8dfb976eb014ee24f3b5a61ccc5bee1b"}, + {file = "pydantic_core-2.20.0-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:d08264b4460326cefacc179fc1411304d5af388a79910832835e6f641512358b"}, + {file = "pydantic_core-2.20.0-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:7a3639011c2e8a9628466f616ed7fb413f30032b891898e10895a0a8b5857d6c"}, + {file = "pydantic_core-2.20.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:05e83ce2f7eba29e627dd8066aa6c4c0269b2d4f889c0eba157233a353053cea"}, + {file = "pydantic_core-2.20.0-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:603a843fea76a595c8f661cd4da4d2281dff1e38c4a836a928eac1a2f8fe88e4"}, + {file = "pydantic_core-2.20.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:ac76f30d5d3454f4c28826d891fe74d25121a346c69523c9810ebba43f3b1cec"}, + {file = "pydantic_core-2.20.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:22e3b1d4b1b3f6082849f9b28427ef147a5b46a6132a3dbaf9ca1baa40c88609"}, + {file = "pydantic_core-2.20.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2761f71faed820e25ec62eacba670d1b5c2709bb131a19fcdbfbb09884593e5a"}, + {file = "pydantic_core-2.20.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a0586cddbf4380e24569b8a05f234e7305717cc8323f50114dfb2051fcbce2a3"}, + {file = "pydantic_core-2.20.0-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:b8c46a8cf53e849eea7090f331ae2202cd0f1ceb090b00f5902c423bd1e11805"}, + {file = "pydantic_core-2.20.0-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:b4a085bd04af7245e140d1b95619fe8abb445a3d7fdf219b3f80c940853268ef"}, + {file = "pydantic_core-2.20.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:116b326ac82c8b315e7348390f6d30bcfe6e688a7d3f1de50ff7bcc2042a23c2"}, + {file = "pydantic_core-2.20.0.tar.gz", hash = "sha256:366be8e64e0cb63d87cf79b4e1765c0703dd6313c729b22e7b9e378db6b96877"}, ] [package.dependencies] @@ -1416,13 +1445,13 @@ typing-extensions = ">=4.6.0,<4.7.0 || >4.7.0" [[package]] name = "pytest" -version = "8.2.1" +version = "8.2.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.2.2-py3-none-any.whl", hash = "sha256:c434598117762e2bd304e526244f67bf66bbd7b5d6cf22138be51ff661980343"}, + {file = "pytest-8.2.2.tar.gz", hash = "sha256:de4bb8104e201939ccdc688b27a89a7be2079b22e2bd2b07f806b6ba71117977"}, ] [package.dependencies] @@ -1749,18 +1778,18 @@ files = [ [[package]] name = "setuptools" -version = "70.0.0" +version = "70.2.0" description = "Easily download, build, install, upgrade, and uninstall Python packages" optional = false python-versions = ">=3.8" files = [ - {file = "setuptools-70.0.0-py3-none-any.whl", hash = "sha256:54faa7f2e8d2d11bcd2c07bed282eef1046b5c080d1c32add737d7b5817b1ad4"}, - {file = "setuptools-70.0.0.tar.gz", hash = "sha256:f211a66637b8fa059bb28183da127d4e86396c991a942b028c6650d4319c3fd0"}, + {file = "setuptools-70.2.0-py3-none-any.whl", hash = "sha256:b8b8060bb426838fbe942479c90296ce976249451118ef566a5a0b7d8b78fb05"}, + {file = "setuptools-70.2.0.tar.gz", hash = "sha256:bd63e505105011b25c3c11f753f7e3b8465ea739efddaccef8f0efac2137bac1"}, ] [package.extras] -docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "pyproject-hooks (!=1.1)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier"] -testing = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "importlib-metadata", "ini2toml[lite] (>=0.14)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "mypy (==1.9)", "packaging (>=23.2)", "pip (>=19.1)", "pyproject-hooks (!=1.1)", "pytest (>=6,!=8.1.1)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-home (>=0.5)", "pytest-mypy", "pytest-perf", "pytest-ruff (>=0.2.1)", "pytest-subprocess", "pytest-timeout", "pytest-xdist (>=3)", "tomli", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] +doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "pyproject-hooks (!=1.1)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier"] +test = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "importlib-metadata", "ini2toml[lite] (>=0.14)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "jaraco.test", "mypy (==1.10.0)", "packaging (>=23.2)", "pip (>=19.1)", "pyproject-hooks (!=1.1)", "pytest (>=6,!=8.1.*)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-home (>=0.5)", "pytest-mypy", "pytest-perf", "pytest-ruff (>=0.3.2)", "pytest-subprocess", "pytest-timeout", "pytest-xdist (>=3)", "tomli", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] [[package]] name = "six" @@ -1773,6 +1802,20 @@ files = [ {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, ] +[[package]] +name = "termcolor" +version = "2.4.0" +description = "ANSI color formatting for output in terminal" +optional = false +python-versions = ">=3.8" +files = [ + {file = "termcolor-2.4.0-py3-none-any.whl", hash = "sha256:9297c0df9c99445c2412e832e882a7884038a25617c60cea2ad69488d4040d63"}, + {file = "termcolor-2.4.0.tar.gz", hash = "sha256:aab9e56047c8ac41ed798fa36d892a37aca6b3e9159f3e0c24bc64a9b3ac7b7a"}, +] + +[package.extras] +tests = ["pytest", "pytest-cov"] + [[package]] name = "tomlkit" version = "0.12.5" @@ -1797,13 +1840,13 @@ files = [ [[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]] @@ -1825,13 +1868,13 @@ zstd = ["zstandard (>=0.18.0)"] [[package]] name = "web3" -version = "6.19.0" +version = "6.20.0" description = "web3.py" optional = false python-versions = ">=3.7.2" files = [ - {file = "web3-6.19.0-py3-none-any.whl", hash = "sha256:fb39683d6aa7586ce0ab0be4be392f8acb62c2503958079d61b59f2a0b883718"}, - {file = "web3-6.19.0.tar.gz", hash = "sha256:d27fbd4ac5aa70d0e0c516bd3e3b802fbe74bc159b407c34052d9301b400f757"}, + {file = "web3-6.20.0-py3-none-any.whl", hash = "sha256:ec09882d21378b688210cf29385e82b604bdc18fe5c2e238bf3b5fe2a6e6dbbc"}, + {file = "web3-6.20.0.tar.gz", hash = "sha256:b04725517502cad4f15e39356eaf7c4fcb0127c7728f83eec8cbafb5b6455f33"}, ] [package.dependencies] @@ -2060,4 +2103,4 @@ multidict = ">=4.0" [metadata] lock-version = "2.0" python-versions = "^3.11" -content-hash = "f2972ca86e61a8d3bfb573e6cec7af96d44f4b99b20e4034b7af1f863554421c" +content-hash = "ca0ca576c7799b86fa2711528c66f3c4650442e36b503be95c72915668cd72bc" diff --git a/testground/benchmark/pyproject.toml b/testground/benchmark/pyproject.toml index 7bde6a3907..129b9fed2c 100644 --- a/testground/benchmark/pyproject.toml +++ b/testground/benchmark/pyproject.toml @@ -14,6 +14,7 @@ tomlkit = "^0" web3 = "^6" hexbytes = "^0" bech32 = "^1" +fire = "^0" [tool.poetry.dev-dependencies] pytest = "^8.2" @@ -24,3 +25,4 @@ build-backend = "poetry.core.masonry.api" [tool.poetry.scripts] testground-testcase = "benchmark.main:main" +stateless-testcase = "benchmark.stateless:main" From 7e1cdcc020d9a70f93890215a2930598349e5015 Mon Sep 17 00:00:00 2001 From: mmsqe Date: Wed, 3 Jul 2024 17:21:16 +0800 Subject: [PATCH 02/15] match test_group_id --- testground/benchmark/benchmark/peer.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/testground/benchmark/benchmark/peer.py b/testground/benchmark/benchmark/peer.py index 7457ed8516..7525bfa94e 100644 --- a/testground/benchmark/benchmark/peer.py +++ b/testground/benchmark/benchmark/peer.py @@ -16,8 +16,8 @@ ACC_INITIAL_AMOUNT = "100000000000000000000000basecro" MEMPOOL_SIZE = 50000 DEFAULT_DENOM = "basecro" -VALIDATOR_GROUP = "validator" -FULLNODE_GROUP = "fullnode" +VALIDATOR_GROUP = "validators" +FULLNODE_GROUP = "fullnodes" CONTAINER_CRONOSD_PATH = "/bin/cronosd" From ceb911766c046ef34aec2f33894b976b08ed8724 Mon Sep 17 00:00:00 2001 From: mmsqe Date: Wed, 3 Jul 2024 19:01:48 +0800 Subject: [PATCH 03/15] lint --- testground/benchmark/benchmark/stateless.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/testground/benchmark/benchmark/stateless.py b/testground/benchmark/benchmark/stateless.py index abc17916f8..cbd41d26df 100644 --- a/testground/benchmark/benchmark/stateless.py +++ b/testground/benchmark/benchmark/stateless.py @@ -8,8 +8,14 @@ import fire from .cli import ChainCommand -from .peer import (CONTAINER_CRONOSD_PATH, FULLNODE_GROUP, VALIDATOR_GROUP, - gen_genesis, init_node, patch_configs) +from .peer import ( + CONTAINER_CRONOSD_PATH, + FULLNODE_GROUP, + VALIDATOR_GROUP, + gen_genesis, + init_node, + patch_configs, +) from .topology import connect_all from .types import PeerPacket from .utils import wait_for_block, wait_for_port From 910b7e3043093bcd75728e970b2bc3cd16b08ce6 Mon Sep 17 00:00:00 2001 From: yihuang Date: Thu, 4 Jul 2024 08:46:29 +0800 Subject: [PATCH 04/15] Update testground/benchmark/benchmark/peer.py Co-authored-by: mmsqe Signed-off-by: yihuang --- testground/benchmark/benchmark/peer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testground/benchmark/benchmark/peer.py b/testground/benchmark/benchmark/peer.py index 7525bfa94e..dd042594c3 100644 --- a/testground/benchmark/benchmark/peer.py +++ b/testground/benchmark/benchmark/peer.py @@ -81,7 +81,7 @@ def init_node( GenesisAccount(address=account_addr, balance=ACC_INITIAL_AMOUNT), ] - node_id = cli("comet", "show-node-id") + node_id = cli("comet", "show-node-id", **default_kwargs) peer_id = f"{node_id}@{ip}:26656" peer = PeerPacket( ip=str(ip), From 0429472e52a71c3a53062b5d2a1eb9f87b8d866c Mon Sep 17 00:00:00 2001 From: huangyi Date: Thu, 4 Jul 2024 12:13:54 +0800 Subject: [PATCH 05/15] change docker-composer --- .../benchmark/compositions/docker-compose.yml | 41 +++++++++++++++---- .../benchmark/compositions/template.yml | 8 ++++ 2 files changed, 42 insertions(+), 7 deletions(-) create mode 100644 testground/benchmark/compositions/template.yml diff --git a/testground/benchmark/compositions/docker-compose.yml b/testground/benchmark/compositions/docker-compose.yml index 1ab74135d8..9a6fd8eb40 100644 --- a/testground/benchmark/compositions/docker-compose.yml +++ b/testground/benchmark/compositions/docker-compose.yml @@ -1,9 +1,36 @@ version: '3' services: - testplan: - image: ghcr.io/crypto-org-chain/cronos-testground:latest - command: stateless-testcase run /data "${VALIDATORS}" - volumes: - - benchmark-volume:/data - deploy: - replicas: 10 + testplan-0: + extends: + file: template.yml + service: testplan-template + environment: + JOB_COMPLETION_INDEX: 0 + + testplan-1: + extends: + file: template.yml + service: testplan-template + environment: + JOB_COMPLETION_INDEX: 1 + + testplan-2: + extends: + file: template.yml + service: testplan-template + environment: + JOB_COMPLETION_INDEX: 2 + + testplan-3: + extends: + file: template.yml + service: testplan-template + environment: + JOB_COMPLETION_INDEX: 3 + + testplan-4: + extends: + file: template.yml + service: testplan-template + environment: + JOB_COMPLETION_INDEX: 4 diff --git a/testground/benchmark/compositions/template.yml b/testground/benchmark/compositions/template.yml new file mode 100644 index 0000000000..57ede019c3 --- /dev/null +++ b/testground/benchmark/compositions/template.yml @@ -0,0 +1,8 @@ +version: '3' +services: + testplan-template: + image: ghcr.io/crypto-org-chain/cronos-testground:latest + command: stateless-testcase run /data "${VALIDATORS}" + volumes: + - ${DATADIR:-"/tmp/data/out"}:/data + - /tmp:/tmp From f1a4aa23a9a779f9e2b50df9b39df7cb8cc08057 Mon Sep 17 00:00:00 2001 From: huangyi Date: Thu, 4 Jul 2024 12:18:14 +0800 Subject: [PATCH 06/15] cleanup --- testground/benchmark/benchmark/peer.py | 2 -- testground/benchmark/benchmark/stateless.py | 1 - 2 files changed, 3 deletions(-) diff --git a/testground/benchmark/benchmark/peer.py b/testground/benchmark/benchmark/peer.py index dd042594c3..bb98b734d3 100644 --- a/testground/benchmark/benchmark/peer.py +++ b/testground/benchmark/benchmark/peer.py @@ -30,7 +30,6 @@ def bootstrap(ctx: Context, cli) -> PeerPacket: ctx.params.chain_id, ctx.params.test_group_id, ctx.group_seq, - ctx.global_seq, ) data = ctx.sync.publish_subscribe_simple( @@ -59,7 +58,6 @@ def init_node( chain_id: str, group: str, group_seq: int, - global_seq: int, ) -> PeerPacket: default_kwargs = { "home": home, diff --git a/testground/benchmark/benchmark/stateless.py b/testground/benchmark/benchmark/stateless.py index cbd41d26df..95ee61560e 100644 --- a/testground/benchmark/benchmark/stateless.py +++ b/testground/benchmark/benchmark/stateless.py @@ -103,7 +103,6 @@ def init_node_local( DEFAULT_CHAIN_ID, group, group_seq, - global_seq, ) From 3871dc2c70424ce1ea6823b8aaaef5a31c0bf6e3 Mon Sep 17 00:00:00 2001 From: mmsqe Date: Thu, 4 Jul 2024 14:02:17 +0800 Subject: [PATCH 07/15] speficy name && disable strict --- testground/benchmark/benchmark/peer.py | 1 + testground/benchmark/compositions/docker-compose.yml | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/testground/benchmark/benchmark/peer.py b/testground/benchmark/benchmark/peer.py index bb98b734d3..451be2f2fe 100644 --- a/testground/benchmark/benchmark/peer.py +++ b/testground/benchmark/benchmark/peer.py @@ -120,6 +120,7 @@ def patch_configs(home: Path, group: str, peers: str): # update persistent_peers and other configs in config.toml config_patch = { "p2p.persistent_peers": peers, + "p2p.addr_book_strict": False, "mempool.recheck": "false", "mempool.size": MEMPOOL_SIZE, "consensus.timeout_commit": "2s", diff --git a/testground/benchmark/compositions/docker-compose.yml b/testground/benchmark/compositions/docker-compose.yml index 9a6fd8eb40..4bf8b88221 100644 --- a/testground/benchmark/compositions/docker-compose.yml +++ b/testground/benchmark/compositions/docker-compose.yml @@ -6,6 +6,7 @@ services: service: testplan-template environment: JOB_COMPLETION_INDEX: 0 + container_name: testplan-0 testplan-1: extends: @@ -13,6 +14,7 @@ services: service: testplan-template environment: JOB_COMPLETION_INDEX: 1 + container_name: testplan-1 testplan-2: extends: @@ -20,6 +22,7 @@ services: service: testplan-template environment: JOB_COMPLETION_INDEX: 2 + container_name: testplan-2 testplan-3: extends: @@ -27,6 +30,7 @@ services: service: testplan-template environment: JOB_COMPLETION_INDEX: 3 + container_name: testplan-3 testplan-4: extends: @@ -34,3 +38,4 @@ services: service: testplan-template environment: JOB_COMPLETION_INDEX: 4 + container_name: testplan-4 From 59e953f758190313426de2f78c3aa353b4914b8b Mon Sep 17 00:00:00 2001 From: huangyi Date: Thu, 4 Jul 2024 14:00:59 +0800 Subject: [PATCH 08/15] run load generator and jsonnet config quit wait for grpc service --- testground/benchmark/benchmark/main.py | 21 ++-------- testground/benchmark/benchmark/sendtx.py | 17 +++++++- testground/benchmark/benchmark/stateless.py | 31 ++++++++------ testground/benchmark/benchmark/utils.py | 5 ++- .../compositions/docker-compose.jsonnet | 17 ++++++++ .../benchmark/compositions/docker-compose.yml | 41 ------------------- .../benchmark/compositions/template.yml | 8 ---- 7 files changed, 57 insertions(+), 83 deletions(-) create mode 100644 testground/benchmark/compositions/docker-compose.jsonnet delete mode 100644 testground/benchmark/compositions/docker-compose.yml delete mode 100644 testground/benchmark/compositions/template.yml diff --git a/testground/benchmark/benchmark/main.py b/testground/benchmark/benchmark/main.py index 0d21f445c6..16c1a652dd 100644 --- a/testground/benchmark/benchmark/main.py +++ b/testground/benchmark/benchmark/main.py @@ -1,6 +1,5 @@ import os import subprocess -from concurrent.futures import ThreadPoolExecutor, as_completed from pathlib import Path import web3 @@ -8,8 +7,8 @@ from .cli import ChainCommand from .context import Context from .peer import CONTAINER_CRONOSD_PATH, bootstrap -from .sendtx import fund_test_accounts, sendtx -from .utils import export_eth_account, wait_for_block, wait_for_port +from .sendtx import generate_load +from .utils import wait_for_block, wait_for_port def influxdb_url(): @@ -37,21 +36,7 @@ def entrypoint(ctx: Context): test_finish_entry = f"finish-test-{ctx.params.test_group_id}" if not ctx.is_validator: - w3 = web3.Web3(web3.providers.HTTPProvider("http://localhost:8545")) - assert w3.eth.chain_id == 777 - genesis_account = export_eth_account(cli, "account") - accounts = fund_test_accounts(w3, genesis_account, ctx.params.num_accounts) - with ThreadPoolExecutor(max_workers=ctx.params.num_accounts) as executor: - futs = ( - executor.submit(sendtx, w3, acct, ctx.params.num_txs) - for acct in accounts - ) - for fut in as_completed(futs): - try: - fut.result() - except Exception as e: - print("test task failed", e) - + generate_load(cli, ctx.params.num_accounts, ctx.params.num_txs) print("finish test", ctx.group_seq) ctx.sync.signal_and_wait( test_finish_entry, ctx.params.test_group_instance_count diff --git a/testground/benchmark/benchmark/sendtx.py b/testground/benchmark/benchmark/sendtx.py index 6fd17696c2..c0752bc34c 100644 --- a/testground/benchmark/benchmark/sendtx.py +++ b/testground/benchmark/benchmark/sendtx.py @@ -1,9 +1,10 @@ import time +from concurrent.futures import ThreadPoolExecutor, as_completed import web3 from eth_account import Account -from .utils import send_transaction +from .utils import export_eth_account, send_transaction TEST_AMOUNT = 1000000000000000000 GAS_PRICE = 1000000000 @@ -54,3 +55,17 @@ def sendtx(w3: web3.Web3, acct: Account, tx_amount: int): if nonce % 100 == 0: print(f"{acct.address} sent {nonce} transactions") + + +def generate_load(cli, num_accounts, num_txs, **kwargs): + w3 = web3.Web3(web3.providers.HTTPProvider("http://localhost:8545")) + assert w3.eth.chain_id == 777 + genesis_account = export_eth_account(cli, "account", **kwargs) + accounts = fund_test_accounts(w3, genesis_account, num_accounts) + with ThreadPoolExecutor(max_workers=num_accounts) as executor: + futs = (executor.submit(sendtx, w3, acct, num_txs) for acct in accounts) + for fut in as_completed(futs): + try: + fut.result() + except Exception as e: + print("test task failed", e) diff --git a/testground/benchmark/benchmark/stateless.py b/testground/benchmark/benchmark/stateless.py index 95ee61560e..6a503d0072 100644 --- a/testground/benchmark/benchmark/stateless.py +++ b/testground/benchmark/benchmark/stateless.py @@ -2,20 +2,16 @@ import os import socket import subprocess +import time from pathlib import Path from typing import List import fire from .cli import ChainCommand -from .peer import ( - CONTAINER_CRONOSD_PATH, - FULLNODE_GROUP, - VALIDATOR_GROUP, - gen_genesis, - init_node, - patch_configs, -) +from .peer import (CONTAINER_CRONOSD_PATH, FULLNODE_GROUP, VALIDATOR_GROUP, + gen_genesis, init_node, patch_configs) +from .sendtx import generate_load from .topology import connect_all from .types import PeerPacket from .utils import wait_for_block, wait_for_port @@ -64,6 +60,8 @@ def run( validators: int, cronosd=CONTAINER_CRONOSD_PATH, global_seq=None, + num_accounts=10, + num_txs=1000, ): outdir = Path(outdir) if global_seq is None: @@ -84,13 +82,20 @@ def run( cli = ChainCommand(cronosd) wait_for_port(26657) wait_for_port(8545) + wait_for_port(9090) wait_for_block(cli, 1) - proc.kill() - try: - proc.wait(5) - except subprocess.TimeoutExpired: - pass + if group == VALIDATOR_GROUP: + # validators don't quit + proc.wait() + else: + generate_load(cli, num_accounts, num_txs, home=home) + + proc.kill() + try: + proc.wait() + except subprocess.TimeoutExpired: + pass def init_node_local( diff --git a/testground/benchmark/benchmark/utils.py b/testground/benchmark/benchmark/utils.py index 7b7a81bc16..37fa318448 100644 --- a/testground/benchmark/benchmark/utils.py +++ b/testground/benchmark/benchmark/utils.py @@ -93,7 +93,8 @@ def send_transaction(w3, tx, acct, wait=True): return txhash -def export_eth_account(cli, name: str) -> Account: +def export_eth_account(cli, name: str, **kwargs) -> Account: + kwargs.setdefault("keyring_backend", "test") return Account.from_key( - cli("keys", "unsafe-export-eth-key", name, keyring_backend="test") + cli("keys", "unsafe-export-eth-key", name, **kwargs) ) diff --git a/testground/benchmark/compositions/docker-compose.jsonnet b/testground/benchmark/compositions/docker-compose.jsonnet new file mode 100644 index 0000000000..f17400a6bc --- /dev/null +++ b/testground/benchmark/compositions/docker-compose.jsonnet @@ -0,0 +1,17 @@ +std.manifestYamlDoc({ + services: { + ['testplan-' + i]: { + image: 'ghcr.io/crypto-org-chain/cronos-testground:latest', + command: 'stateless-testcase run /data 3 --num_accounts=10 --num_txs=1000', + container_name: 'testplan-' + i, + volumes: [ + @'${DATADIR:-/tmp/data/out}:/data', + '/tmp:/tmp', + ], + environment: { + JOB_COMPLETION_INDEX: i, + }, + } + for i in std.range(0, 10) + }, +}) diff --git a/testground/benchmark/compositions/docker-compose.yml b/testground/benchmark/compositions/docker-compose.yml deleted file mode 100644 index 4bf8b88221..0000000000 --- a/testground/benchmark/compositions/docker-compose.yml +++ /dev/null @@ -1,41 +0,0 @@ -version: '3' -services: - testplan-0: - extends: - file: template.yml - service: testplan-template - environment: - JOB_COMPLETION_INDEX: 0 - container_name: testplan-0 - - testplan-1: - extends: - file: template.yml - service: testplan-template - environment: - JOB_COMPLETION_INDEX: 1 - container_name: testplan-1 - - testplan-2: - extends: - file: template.yml - service: testplan-template - environment: - JOB_COMPLETION_INDEX: 2 - container_name: testplan-2 - - testplan-3: - extends: - file: template.yml - service: testplan-template - environment: - JOB_COMPLETION_INDEX: 3 - container_name: testplan-3 - - testplan-4: - extends: - file: template.yml - service: testplan-template - environment: - JOB_COMPLETION_INDEX: 4 - container_name: testplan-4 diff --git a/testground/benchmark/compositions/template.yml b/testground/benchmark/compositions/template.yml deleted file mode 100644 index 57ede019c3..0000000000 --- a/testground/benchmark/compositions/template.yml +++ /dev/null @@ -1,8 +0,0 @@ -version: '3' -services: - testplan-template: - image: ghcr.io/crypto-org-chain/cronos-testground:latest - command: stateless-testcase run /data "${VALIDATORS}" - volumes: - - ${DATADIR:-"/tmp/data/out"}:/data - - /tmp:/tmp From 9d94f94f16a804dfb3acb82c34df595d6dd1f8b1 Mon Sep 17 00:00:00 2001 From: huangyi Date: Thu, 4 Jul 2024 15:45:34 +0800 Subject: [PATCH 09/15] fix lint --- testground/benchmark/benchmark/stateless.py | 11 ++++++++--- testground/benchmark/benchmark/utils.py | 4 +--- testground/benchmark/pyproject.toml | 6 ++++++ 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/testground/benchmark/benchmark/stateless.py b/testground/benchmark/benchmark/stateless.py index 6a503d0072..3102e9dfc7 100644 --- a/testground/benchmark/benchmark/stateless.py +++ b/testground/benchmark/benchmark/stateless.py @@ -2,15 +2,20 @@ import os import socket import subprocess -import time from pathlib import Path from typing import List import fire from .cli import ChainCommand -from .peer import (CONTAINER_CRONOSD_PATH, FULLNODE_GROUP, VALIDATOR_GROUP, - gen_genesis, init_node, patch_configs) +from .peer import ( + CONTAINER_CRONOSD_PATH, + FULLNODE_GROUP, + VALIDATOR_GROUP, + gen_genesis, + init_node, + patch_configs, +) from .sendtx import generate_load from .topology import connect_all from .types import PeerPacket diff --git a/testground/benchmark/benchmark/utils.py b/testground/benchmark/benchmark/utils.py index 37fa318448..45782a05d3 100644 --- a/testground/benchmark/benchmark/utils.py +++ b/testground/benchmark/benchmark/utils.py @@ -95,6 +95,4 @@ def send_transaction(w3, tx, acct, wait=True): def export_eth_account(cli, name: str, **kwargs) -> Account: kwargs.setdefault("keyring_backend", "test") - return Account.from_key( - cli("keys", "unsafe-export-eth-key", name, **kwargs) - ) + return Account.from_key(cli("keys", "unsafe-export-eth-key", name, **kwargs)) diff --git a/testground/benchmark/pyproject.toml b/testground/benchmark/pyproject.toml index 129b9fed2c..c7b4b2d1c1 100644 --- a/testground/benchmark/pyproject.toml +++ b/testground/benchmark/pyproject.toml @@ -26,3 +26,9 @@ build-backend = "poetry.core.masonry.api" [tool.poetry.scripts] testground-testcase = "benchmark.main:main" stateless-testcase = "benchmark.stateless:main" + +[tool.black] +line-length = 88 + +[tool.isort] +profile = "black" From 753ceef19cef718cbeda8692efe1c18b8d6cbf2b Mon Sep 17 00:00:00 2001 From: huangyi Date: Thu, 4 Jul 2024 16:00:19 +0800 Subject: [PATCH 10/15] readme and flake --- flake.nix | 4 ++++ testground/README.md | 27 +++++++++++++++++++++++++++ testground/benchmark/flake.nix | 12 +++++++++--- 3 files changed, 40 insertions(+), 3 deletions(-) diff --git a/flake.nix b/flake.nix index b1fdcda4a3..5b3887fecc 100644 --- a/flake.nix +++ b/flake.nix @@ -42,6 +42,10 @@ apps = { cronosd = mkApp packages.cronosd; cronosd-testnet = mkApp packages.cronosd-testnet; + stateless-testcase = { + type = "app"; + program = "${pkgs.testground-testcase}/bin/stateless-testcase"; + }; }; defaultPackage = packages.cronosd; defaultApp = apps.cronosd; diff --git a/testground/README.md b/testground/README.md index c24d9e54da..f00824aaef 100644 --- a/testground/README.md +++ b/testground/README.md @@ -1,3 +1,5 @@ +# Testground + [Testground documentation](https://docs.testground.ai/) ## Build Image @@ -67,3 +69,28 @@ mounts: writable: true ``` + + +# Stateless Mode + +To simplify cluster setup, we introduce a stateless mode. + +## Generate Data Files Locally + +You need to have a `cronosd` in `PATH`. + +```bash +$ nix run github:crypto-org-chain/cronos#stateless-testcase gen /tmp/data/out 3 7 +``` + +## Run In Local Docker + +```bash +$ jsonnet -S testground/benchmark/compositions/docker-compose.jsonnet | docker-compose -f /dev/stdin up +``` + +It'll mount the data files to all the containers. + +## Run In Cluster + +TODO diff --git a/testground/benchmark/flake.nix b/testground/benchmark/flake.nix index e4b9fabafb..3883096eed 100644 --- a/testground/benchmark/flake.nix +++ b/testground/benchmark/flake.nix @@ -64,9 +64,15 @@ in rec { packages.default = pkgs.testground-testcase; - apps.default = { - type = "app"; - program = "${pkgs.testground-testcase}/bin/testground-testcase"; + apps = { + default = { + type = "app"; + program = "${pkgs.testground-testcase}/bin/testground-testcase"; + }; + stateless-testcase = { + type = "app"; + program = "${pkgs.testground-testcase}/bin/stateless-testcase"; + }; }; devShells.default = pkgs.mkShell { buildInputs = [ pkgs.testground-testcase-env ]; From 092f4821d91fff418b610bac3ab2c00df47e3e7b Mon Sep 17 00:00:00 2001 From: mmsqe Date: Thu, 4 Jul 2024 16:01:03 +0800 Subject: [PATCH 11/15] fix total --- testground/benchmark/compositions/docker-compose.jsonnet | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testground/benchmark/compositions/docker-compose.jsonnet b/testground/benchmark/compositions/docker-compose.jsonnet index f17400a6bc..bec5e017f7 100644 --- a/testground/benchmark/compositions/docker-compose.jsonnet +++ b/testground/benchmark/compositions/docker-compose.jsonnet @@ -12,6 +12,6 @@ std.manifestYamlDoc({ JOB_COMPLETION_INDEX: i, }, } - for i in std.range(0, 10) + for i in std.range(0, 9) }, }) From 8ecd342938efb7b0912aa241a4d4bb7a76a0dbb2 Mon Sep 17 00:00:00 2001 From: mmsqe Date: Thu, 4 Jul 2024 16:01:27 +0800 Subject: [PATCH 12/15] print tps --- testground/benchmark/benchmark/main.py | 10 ++-------- testground/benchmark/benchmark/sendtx.py | 8 ++++++++ testground/benchmark/benchmark/stateless.py | 4 ++-- 3 files changed, 12 insertions(+), 10 deletions(-) diff --git a/testground/benchmark/benchmark/main.py b/testground/benchmark/benchmark/main.py index 16c1a652dd..47f9dbfd92 100644 --- a/testground/benchmark/benchmark/main.py +++ b/testground/benchmark/benchmark/main.py @@ -2,12 +2,10 @@ import subprocess from pathlib import Path -import web3 - from .cli import ChainCommand from .context import Context from .peer import CONTAINER_CRONOSD_PATH, bootstrap -from .sendtx import generate_load +from .sendtx import collect_output, generate_load from .utils import wait_for_block, wait_for_port @@ -43,11 +41,7 @@ def entrypoint(ctx: Context): ) if ctx.is_fullnode_leader: - # collect output - w3 = web3.Web3(web3.providers.HTTPProvider("http://localhost:8545")) - for i in range(w3.eth.block_number): - blk = w3.eth.get_block(i) - print(i, len(blk.transactions), blk.timestamp) + collect_output() # halt after all tasks are done ctx.sync.signal_and_wait("halt", ctx.params.test_instance_count) diff --git a/testground/benchmark/benchmark/sendtx.py b/testground/benchmark/benchmark/sendtx.py index c0752bc34c..6432ec4245 100644 --- a/testground/benchmark/benchmark/sendtx.py +++ b/testground/benchmark/benchmark/sendtx.py @@ -69,3 +69,11 @@ def generate_load(cli, num_accounts, num_txs, **kwargs): fut.result() except Exception as e: print("test task failed", e) + + +def collect_output(): + # collect output + w3 = web3.Web3(web3.providers.HTTPProvider("http://localhost:8545")) + for i in range(w3.eth.block_number): + blk = w3.eth.get_block(i) + print(i, len(blk.transactions), blk.timestamp) diff --git a/testground/benchmark/benchmark/stateless.py b/testground/benchmark/benchmark/stateless.py index 3102e9dfc7..e105e8feb9 100644 --- a/testground/benchmark/benchmark/stateless.py +++ b/testground/benchmark/benchmark/stateless.py @@ -16,7 +16,7 @@ init_node, patch_configs, ) -from .sendtx import generate_load +from .sendtx import collect_output, generate_load from .topology import connect_all from .types import PeerPacket from .utils import wait_for_block, wait_for_port @@ -95,7 +95,7 @@ def run( proc.wait() else: generate_load(cli, num_accounts, num_txs, home=home) - + collect_output() proc.kill() try: proc.wait() From 8248973eeb2901ace8eaeea9bb90cfdae4bf138b Mon Sep 17 00:00:00 2001 From: yihuang Date: Fri, 5 Jul 2024 09:46:57 +0800 Subject: [PATCH 13/15] Update testground/README.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> Signed-off-by: yihuang --- testground/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testground/README.md b/testground/README.md index f00824aaef..8d03f11b76 100644 --- a/testground/README.md +++ b/testground/README.md @@ -73,7 +73,7 @@ mounts: # Stateless Mode -To simplify cluster setup, we introduce a stateless mode. +To simplify cluster setup, we are introducing a stateless mode. ## Generate Data Files Locally From db5170f8357a31702a84f2d43212cf6ce30747c7 Mon Sep 17 00:00:00 2001 From: mmsqe Date: Fri, 5 Jul 2024 09:48:26 +0800 Subject: [PATCH 14/15] Revert "print tps" This reverts commit 8ecd342938efb7b0912aa241a4d4bb7a76a0dbb2. --- testground/benchmark/benchmark/main.py | 10 ++++++++-- testground/benchmark/benchmark/sendtx.py | 8 -------- testground/benchmark/benchmark/stateless.py | 4 ++-- 3 files changed, 10 insertions(+), 12 deletions(-) diff --git a/testground/benchmark/benchmark/main.py b/testground/benchmark/benchmark/main.py index 47f9dbfd92..16c1a652dd 100644 --- a/testground/benchmark/benchmark/main.py +++ b/testground/benchmark/benchmark/main.py @@ -2,10 +2,12 @@ import subprocess from pathlib import Path +import web3 + from .cli import ChainCommand from .context import Context from .peer import CONTAINER_CRONOSD_PATH, bootstrap -from .sendtx import collect_output, generate_load +from .sendtx import generate_load from .utils import wait_for_block, wait_for_port @@ -41,7 +43,11 @@ def entrypoint(ctx: Context): ) if ctx.is_fullnode_leader: - collect_output() + # collect output + w3 = web3.Web3(web3.providers.HTTPProvider("http://localhost:8545")) + for i in range(w3.eth.block_number): + blk = w3.eth.get_block(i) + print(i, len(blk.transactions), blk.timestamp) # halt after all tasks are done ctx.sync.signal_and_wait("halt", ctx.params.test_instance_count) diff --git a/testground/benchmark/benchmark/sendtx.py b/testground/benchmark/benchmark/sendtx.py index 6432ec4245..c0752bc34c 100644 --- a/testground/benchmark/benchmark/sendtx.py +++ b/testground/benchmark/benchmark/sendtx.py @@ -69,11 +69,3 @@ def generate_load(cli, num_accounts, num_txs, **kwargs): fut.result() except Exception as e: print("test task failed", e) - - -def collect_output(): - # collect output - w3 = web3.Web3(web3.providers.HTTPProvider("http://localhost:8545")) - for i in range(w3.eth.block_number): - blk = w3.eth.get_block(i) - print(i, len(blk.transactions), blk.timestamp) diff --git a/testground/benchmark/benchmark/stateless.py b/testground/benchmark/benchmark/stateless.py index e105e8feb9..3102e9dfc7 100644 --- a/testground/benchmark/benchmark/stateless.py +++ b/testground/benchmark/benchmark/stateless.py @@ -16,7 +16,7 @@ init_node, patch_configs, ) -from .sendtx import collect_output, generate_load +from .sendtx import generate_load from .topology import connect_all from .types import PeerPacket from .utils import wait_for_block, wait_for_port @@ -95,7 +95,7 @@ def run( proc.wait() else: generate_load(cli, num_accounts, num_txs, home=home) - collect_output() + proc.kill() try: proc.wait() From 9e798f1a62ee1a8b218e4e3ad32c652454c0814c Mon Sep 17 00:00:00 2001 From: mmsqe Date: Fri, 5 Jul 2024 09:48:53 +0800 Subject: [PATCH 15/15] kill directly --- testground/benchmark/benchmark/stateless.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/testground/benchmark/benchmark/stateless.py b/testground/benchmark/benchmark/stateless.py index 3102e9dfc7..6a93fa95d8 100644 --- a/testground/benchmark/benchmark/stateless.py +++ b/testground/benchmark/benchmark/stateless.py @@ -97,10 +97,6 @@ def run( generate_load(cli, num_accounts, num_txs, home=home) proc.kill() - try: - proc.wait() - except subprocess.TimeoutExpired: - pass def init_node_local(