diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index c79a291..d837188 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,25 +1,25 @@ repos: - repo: https://github.com/psf/black - rev: 24.3.0 + rev: 24.10.0 hooks: - id: black language_version: python3.10 - repo: https://github.com/pre-commit/mirrors-mypy - rev: v1.2.0 # Updated to the desired version of mypy + rev: v1.13.0 # Updated to the desired version of mypy hooks: - id: mypy language_version: python3.10 - repo: https://github.com/python-poetry/poetry - rev: 1.4.0 + rev: 1.8.2 hooks: - id: poetry-check - repo: https://github.com/pycqa/flake8 - rev: 6.0.0 + rev: 6.1.0 hooks: - id: flake8 additional_dependencies: [Flake8-pyproject] - repo: https://github.com/pycqa/isort - rev: 5.12.0 + rev: 5.13.2 hooks: - id: isort name: isort (python) diff --git a/README.md b/README.md index 3e2a4a1..50e6e08 100644 --- a/README.md +++ b/README.md @@ -195,12 +195,12 @@ Chainbench will keep the test data up to date by running a background process th ### Monitors Monitors are separate processes that run during the test to collect or process some additional data and metrics relevant to the test. -For example, head-lag-monitor will collect the latest block information from the node under test, check the timestamp and compare it to current time to calculate how much the node lags behind. +For example, sync-lag-monitor will collect the latest block information from the node under test, check the timestamp and compare it to current time to calculate how much the node lags behind. You may include monitors in your test by using the `-m` or `--monitor` option and specifying the name of the monitor. At the moment, monitors only work in headless mode. Here's an example: ```shell -chainbench start --profile evm.light --users 50 --workers 2 --test-time 12h --target https://node-url --headless --autoquit -m head-lag-monitor +chainbench start --profile evm.light --users 50 --workers 2 --test-time 12h --target https://node-url --headless --autoquit -m sync-lag-monitor ``` diff --git a/chainbench/main.py b/chainbench/main.py index ba4f02f..2c697ec 100644 --- a/chainbench/main.py +++ b/chainbench/main.py @@ -8,8 +8,10 @@ import click import gevent.pool from click import Context, Parameter +from locust.argument_parser import parse_locustfile_paths +from locust.util.load_locustfile import load_locustfile -from chainbench.user import get_subclass_tasks +from chainbench.user import EvmUser, SolanaUser, get_subclass_tasks from chainbench.user.common import all_method_classes, all_methods from chainbench.util.cli import ( ContextData, @@ -148,7 +150,7 @@ def validate_profile(ctx: Context, param: Parameter, value: str) -> str: default=[], help="Add a monitor to collect additional data or metrics. " "You may specify this option multiple times for different monitors", - type=click.Choice(["head-lag-monitor"], case_sensitive=False), + type=click.Choice(["sync-lag-monitor"], case_sensitive=False), multiple=True, ) @click.option( @@ -251,18 +253,16 @@ def start( click.echo(f"Profile path {profile_path} does not exist.") sys.exit(1) + user_classes = {} + for locustfile in parse_locustfile_paths([profile_path.__str__()]): + _, _user_classes, _ = load_locustfile(locustfile) + for key, value in _user_classes.items(): + user_classes[key] = value + test_data_types = set() + for user_class in user_classes.values(): + test_data_types.add(type(getattr(user_class, "test_data")).__name__) + if test_by_directory: - from locust.argument_parser import parse_locustfile_paths - from locust.util.load_locustfile import load_locustfile - - user_classes = {} - test_data_types = set() - for locustfile in parse_locustfile_paths([profile_path.__str__()]): - _, _user_classes, _ = load_locustfile(locustfile) - for key, value in _user_classes.items(): - user_classes[key] = value - for user_class in user_classes.values(): - test_data_types.add(type(getattr(user_class, "test_data")).__name__) if len(test_data_types) > 1: click.echo( "Error occurred: Multiple test data types detected. " @@ -384,9 +384,14 @@ def start( tags=["loudspeaker"], ) + if list(test_data_types)[0] == "SolanaTestData": + user: type[SolanaUser] | type[EvmUser] = SolanaUser + else: + user = EvmUser + unique_monitors: set[str] = set(monitor) for m in unique_monitors: - p = Process(target=monitors[m], args=(target, results_path, test_time)) + p = Process(target=monitors[m], args=(user, target, results_path, test_time)) click.echo(f"Starting monitor {m}") p.start() ctx.obj.monitors.append(p) @@ -505,7 +510,7 @@ def shapes() -> None: ) def methods() -> None: for method_class in all_method_classes: - click.echo(f"\nMethods for {method_class.__name__}:") + click.echo(f"\nMethods for {method_class.__name__}: ") task_list = get_subclass_tasks(method_class) for task in task_list: click.echo(f"- {method_class.task_to_method(task.name)}") diff --git a/chainbench/test_data/solana.py b/chainbench/test_data/solana.py index eb71845..73120a3 100644 --- a/chainbench/test_data/solana.py +++ b/chainbench/test_data/solana.py @@ -153,7 +153,7 @@ def get_random_account(self, rng: RNG | None = None) -> Account: return self.get_random_block(rng).get_random_account(rng) @staticmethod - def get_random_token_address(self, rng: RNG | None = None) -> Account: + def get_random_token_address(rng: RNG | None = None) -> Account: if rng is None: rng = get_rng() token_addresses = [ @@ -162,5 +162,198 @@ def get_random_token_address(self, rng: RNG | None = None) -> Account: "5fTwKZP2AK39LtFN9Ayppu6hdCVKfMGVm79F2EgHCtsi", # WHEYO "NeonTjSjsuo3rexg9o6vHuMXw62f9V7zvmu8M8Zut44", # Neon EVM "8BMzMi2XxZn9afRaMx5Z6fauk9foHXqV5cLTCYWRcVje", # Staika + "EKpQGSJtjMFqKZ9KQanSqYXRcF8fBopzLHYxdM65zcjm", # dogwifhat + "JUPyiwrYJFskUPiHa7hkeR8VUtAeFoSYbKedZNsDvCN", # Jupiter + "DezXAZ8z7PnrnRJjz3wXBoRgixCa6xjnB7YaB1pPB263", # Bonk + "HZ1JovNiVvGrGNiiYvEozEVgZ58xaU3RKwX8eACQBCt3", # Pyth ] return rng.random.choice(token_addresses) + + @staticmethod + def get_random_token_account(rng: RNG | None = None) -> Account: + if rng is None: + rng = get_rng() + token_accounts = [ + "CF34PLYZfTMteS2mR3VzxsHjk6VXfCTnAcnwaEGJrknt", + "97DxJzDxY71ofivxpNuNyKYcZy824zJWAXYemM5Md4Dt", + "FE2BNorsuDMFDQ8XNkDfxp5x2H59qviowi39RVBzPf2S", + "2CR6HNJrq8g6auzwpQiVP2TcbE2gAPZxGT16pTU6h13g", + "4ZFd7tmfZzoyinBR1mWSr5FfmjdyvmbZ7DMMhUjrx7jW", + "FTUTbTrWdxctBh4DrYTK8Scrtnj52KMSYbc1RS9ytF6J", + "2eZAfcCyxPwxxqK9gVfzPcJH1jrnfa2xZggy1RFEiDHd", + "6ttf7G7FR9GWqxiyCLFNaBTvwYzTLPdbbrNcRvShaqtS", + "62KEKuC6yPmKy7M1PJjk8EWuouuF1srk4rxwPptsoySh", + "EaDGsTov6CvsZZeo16cbrrtUE8J9gjkSPis5c6SiSHEH", + "FcTsmtRX9wNFhiviJbW5YgG3PKXDNQtemQA5zNL2W1pW", + "HmrKnggYYcNVwF8S7L1nno7LCKzobDBjX5UBuzFZukYj", + "5nox3B41bSNtJV3s7gFPWVK8JtdaZ4QxCVxrhpGgnw4B", + "GoBAZzgSLnoc5mXuUHgMLKsqYX7BFrdgwQYJL2cApgmX", + "3GXyFi89uNvGPngFi65NYsWxxHTWDbJQtM1ntjGfn2gK", + "4T6FHkAmoW21ia1GWDT5KBMd83kjwrPiXx4QYTkxz899", + "FwrCxkDG1vahAHeGi1Wr5mBgLyayUvCy3d1tbnhsAQ99", + "EYVDkQXrjNwwpxw3m2EojnFJgyTVuan77XxMs2hbBk34", + "4BedR6CnQRtHq3aMVcHcFaU9sT1Wns2vEKah7ATFimY7", + "3eApKHDU4GpXD2L1uZ3CQGMj2bAq6grhdZz9zsf9xacr", + "8gesfhmNebstEuFovKzFgaeq5LPtjM2esrq6JA4eQadJ", + "ANjPXGaMSho5dp5A78osdTAYhWrt8o2DVQEjPhd2pZrW", + "EvcsKVtsH92KvvAfA6SbWGA4ShTTTsWZt48KTdCuCd3Y", + "7znyJ3N4K26BmispS6z7TNWfar61KzFiqbx4pYmtG4dN", + "3zQXNfbzwp9L3UbwMe3JsSjB6eT9Wcx8B5RQ2VS1G2fL", + "7mfvcxhqSzqQ9iTHqDqugC3HVBcnvoFsdgWEjLyykx3E", + "GJscPZ2xzayPa8QXW2Xi2WJPHaj2k1TQDShbhYJUHR94", + "3shgyeu9cy8xkkRwDENKnsYXxsCUkc5suq3aYXi912XW", + "3FGoU3eRepLeK5ZD1jA4GhSWw7GUYhsJwPBB5Qfihrmt", + "3voYsgqCZEWvyG8xSkNhgqYb9ciKNjzXX91JwesqdasT", + "G58QLCn2H2TvtoPT5uwT8tjpYAUa1CzWsbKJXUPqMaJ4", + "J5jtM83Eoyn1TQdxu1hRC96dLy4ZgenN9vf6Fk5jLe9V", + "GvZ4emMJfgW9U2nfw145FraS2BMJyGsmoji8eWi11d6j", + "DugPkEmWHgTSXNMGAD9r3SbL7MgDrnuHuSeH695tN8FQ", + "39uZe8NUJJVnNmQ6nA6VxQFwQ3GqypvtVrnhSLbByRBr", + "8zBEBGcPZBVqu6fRmxsiXCEG4ehvh3TEiy8gq6q6E6YL", + "4bEcyAvz5zSzFwAnEAHGSsUG1EASMnbJSDPSipPKStti", + "DTbktzGachmQVW1sH7sNxCYrs3YpcEtyDuBcHAWr6y3t", + "HQvP9mRNpZBXi3CMsp2vP2H8qaGAFeQobArX455Ugoh9", + "4iSr7wAsfe9ohXSS2Z6v2icV94X81hPtPLLvt6ss84yb", + "3d1Vr3n7cdzhk3vrSn2eXm8H3gqSircLVqwqcEKc4AX2", + "4zHS6gTzBRXpJojhJgHQRCVYhMAdDBHW2QSU7SNMtXh9", + "JguSE1vBoUUSN7MxZBHKJHjXxECW7d12xLPLzVV7SYi", + "zGWrqUkuhmtHA8G7JJ3mxbbAxxRYpC2GXWnKyYMFDM2", + "4ehpyuufJtzt49CtJYaN3HLDYYMotvR34WKkFBNe4fDv", + "HsrDHXyWT6gNPnHPSMgoHpQxLSqMcsyJCXLvp4oxhoV7", + "B4kZTkeZCTnHf3J6pWC9deHUx4BWU8cZPewY6PtWYS3s", + "HjVvBA8HX3ZxA9wAziApGXTQsZnLTtDxQa9ymSCkke64", + "8M23uCAp1Wc3jTKhq7nzTxqKK54XVdDwSLspv1x4Yigs", + "DW8awKneKxcep9iouLeNwWRAzC6rz9sLKAgENpXL6BBd", + "HU5CJ61HKmWfBzK6jrD2q6o17iwrkf3T9xqrdBgPBR5F", + "2yobwT8wsq6y4fbEkdnZk5Mj42hiAZW6tyiLU4KjhPVc", + "9vujwMDWRHfXSHs1oTEUXcUUwWmev4gf2mzJ2FzNbmkq", + "2wkdLjUEmaQ88Ut1hi5vRFoFgSpovz8x9xj8nhURTKJB", + "Cdigh3iZD8DvHTnNyC4Sm7uiNhiFmY2EcpfCviLG2AEC", + "7ZHAcG8T12tWeSgvvTNDE3hskFfXRaVe3PRMjvEAzCC4", + "5m1gS9Sphbvt4zDCu6gqFqVcekCX8eAtfwJjPDMUVvxJ", + "9HHMyRMeYSyeR45LSnHHvpofq8cnX2dShUg5zmHsDpiA", + "4WMDNjMpKLEbC4oqAeTchN5WjwjJrnZdTzmpTqdeJoc8", + "r1RNBu4Grexhe9AsK1cakgyzh93uxmXzeKk7jApVhKf", + "CfE7AzLsSsEBSsQgWAvXes9qfQmE7WYJTdApMefu8ZaM", + "HSizfxkFyeUssoVvzgjkgArQ4RFyKZWMmHU554Ya9V6R", + "9okWmESkYFw3Jmk3KxRijp2TMM21YHAGaUFRZNUoDFjP", + "FRojFj9xyuFtePNn4xuqPzZU8CLyLpAaYPwf7aG8gotJ", + "A5zrmTFMPpTWhSxay8gDr3rLr4WguCPYp8um5ywRFeCT", + "8VWPNtQvjSGrot14cgBSgNDKJhLvFaodcpY9dFGZJx1z", + "3PqVf4rm7Yx1GqdND9Q6mMormXfFZRvTJdBFwBEGdobB", + "C3EJkyHWfAn9mZBi6SneEp57VvpYNxVnqE9AtwmvAuo", + "9x2FRfDMAiDBSZPR5HJje6bpAH8XHkeqedBopbwu9g1H", + "gi9vP3V2p5mDYURGNo7CPcEfR1tMp3sxjbQ1AHvpyxZ", + "BbLCUYHyYcRJCfzgoow96MSMb3EKdHWL4ALq3YNJpA2z", + "HfAK56UE6pLwBM1kQxn1vAk5W6sRBrSE8KrndCooR5Kx", + "G6g2193UQA3N8byF9D7cDn5tYhAt6gbNB9zLNHZYJJaH", + "3MXL9RNyHJcg3wYUBsbDLQyNTyJJRftZMzg7bxPsdFGf", + "3bFoTw6XoeuYd1qMCQCQTf7EJoQHXjgJUB8W9FoSESY1", + "BxQSVGUcfWt2k5AZ58rKxwxdCau2NXa9yt9osmDWU9hJ", + "GSHsTFMNMtAyFP6PxDKvTHDDBzzZYUFQnqFumtcLFicc", + "Fm5iBQMZxuH5XMNMd7RcfYxQuxhGNXsLZ5SZ5rLXnCGF", + "6Y7xRKGwL1ok12NnkwNhAtumqb7ugZ9xvCYrnMB8Xviv", + "H4BdrSaFofoeQRUH4g5fY9tgRc1yqCdEryETKnW26tbm", + "CTh1akv2g7hRsBUFdjLrNW6TzAe34AukJBNsYw5sUH5s", + "6fbPJiBdXAoN4qkXuxMwUNZUF77WxfeDPCznWCxVPdL2", + "C4hXRxKmfucqNDndwYASSDm7EbPcoXG3LPFULdXP5MUh", + "8kfrPrNzFv3ouvQBP4JwmA9upRu4uDAXf8WP7gmsRevA", + "8PvETn7pxGE7ZwLUxQbob3zXcx8SFYEaKujWXkVdyzy8", + "86nsBYZV6UyuiRqK5PyMKpbJAMkay7aLyfBieYjFw383", + "7LBGStihbxoBAWtqDiVzTSg8ci6y74Ws2bbd2xiyXk35", + "DGKpmnNkmKzgMsrJQsP9dYzxRChcf5PbhDA8Z24Mm9L9", + "3Xjac1TpCgtW8U5RBenzmWwUfsNXhNAn7jdvvgURDped", + "GLVvAEsrWc5vhknQdkVyDkyzgQ2kFzh4NhfqADYxzLZb", + "9YzDwNLK5C7ZEKhYiNt27gbNejpdEoeTfKyTFwDsjfgy", + "7Xi29v2bqBx4DNbVq1LA8WJPuyLiRPqCxxBBZBnNsumu", + "BKqEQy6E4Pa2yAEssbQS1PfbjQCfKSmrjqNCtemY8dKk", + "TsG1nsBvMxKULXtiAgH3iUatrFzihw9MgHyz6VGHSSJ", + "HthTrkvsRA1sAuWRJmP4UAB37VT2RTgT7QFWvWKMRey", + "5SR9UtKUJpXRFd3W1bnNjS44vJuoFQyAznoESzGA7M1r", + "Eqz4J57GkmPq2P2U8yWGQspUB8FWBLnidoPhMcvWS1Jx", + "A6JCe9BDEby7fsevUbzTqU9jFBbkHwSuDmJGhoPLy44L", + "Grh57JBjPDYeTwSqNsQ8i3ks2HJsq5HxCFHpqhNcWiDi", + "CDeni3XaGkCrbN8Wm2PwmFHnk3ce9cEFbitRC1NNxxrE", + "7XX64f8UKE1nxNCSwncCUj3c2FJYdXHmDV5xd5DRdFky", + "EHDnHqX6PtnSdPfsnnr1oWtmQbenDwqZAKUo5QAq9Ro3", + "1LLLyMZvAdimbcsC4Xp7GVWiJScztEpfXVR9upyxq5G", + "DsxpGaCZ13aUfDDz2CSjuzCA8XJJYLuGsV65KXdyLWdW", + "Fm7yBTcuUDBdzj2PbP6tr8uiFAJwS53kNQbwEERHP65A", + "EdhM4qGK29P2X1GsRYZtF8E5v9rkd52NRXEh1d8BzUc8", + "4kT3EXc5dDVndUU9mV6EH3Jh3CSEvpcCZjuMkwqrtxUy", + "GqzXwoPv8TJtxqDDB1G3Q35MQpor6433fdB18vdNYfqC", + "AaJyLPfJoJFcUHHH7VDWsqyVPb7aMAwcRHB2Z7YXt2La", + "6sJ9tDgWmQxkEZSk8xihYiJUpmFL3fdgLQ6DayCSDR2U", + "7VKFsPJooGLrWvMqyjvfTucUQRKzop6iErPGw4S2r69K", + "DNnGKYfnrQirEr2Z1145WLLtRCwtaZh8PpzijrWUDKMr", + "3MWHzLgLQ98n4htEJXKJWNUNUfbeexWEDnksRFxDsLeS", + "6fafNTqhRyQ4Q3cwD9VVhXZAVCtL1YYW2kSKTD3ytBse", + "AUmMMDCvmghtsrn5T6EzcJBiaSApv5P4d2XVQdZAg1vp", + "BADVD1RWzAXDd62Fj6RPTnmFwXxviRjxpvSaidarHDc9", + "2Dyj8L9kv4wSK4sXyfcduoYoPUouSQWsuv9THm11cvEh", + "GygCQjU9eTr3WivrstviJhJqbDL4tnoAjGXCGo1XzEub", + "CBzCGSmuNKKrGjMQLQ1ihkbVUJRATavcsd6rdiZ2CFv7", + "pC2qrgQNnKZ87JxBrULrZiLhEQim8SpchAxAKnqDnya", + "26ddLrqXDext6caX1gRxARePN4kzajyGiAUz9JmzmTGQ", + "6G4XDSge4txj5tBkA5gZqefXXE3BRxqA37Yb1pmrHv6N", + "7bEL9XkPGNg7a3oSiUERKsZtFoJMqKh6VhGDCmMCPqdg", + "K6U4dQ8jANMEqQQycXYiDcf3172NGefpQBzdDbavQbA", + "GDijXRGfd1jhk5GkRPp1TDnEH2FfHURSRZeB5um3pUWk", + "DWVtxR7oo3uTiuM3o1cCxTJ5wM8Wnjvu1apwMkQhdedY", + "B3NG3yTDwf3sL1oCUvf39HtdzWbtYoinNWqKDoRJTeuH", + "CeLRs4kchQbWEcqZf7ctGrYhXwbU89fVxRs4Q34XeiHq", + "GQrdtzmAsXpb5pPsENC68jXF6YwmME235ZJpRoKh5F5R", + "ASehmX2sjG1Qz7MQyLJu8wBoV2Xx8cCV3uU8VbBDGQJQ", + "649KG5AEPic6MDVdbXjLPWj3vy6Lc466qGjV9d5Y3VyZ", + "FGHwSJMx8yvMMmfiZSd5jmL7KbbbubVpNrhYX7NXPCdu", + "E6FLdjDBtHvzhMGihcbec34KfcAqSYW67kfJV8RAKH1f", + "mGmik7Qf2YdrSZjTsS3ciZn4xyqiVHYUP7cfjQDT5he", + "6QxycVhn6Zak2ky4HAEEanz85ockBaEfHxgtqPP7Mo1a", + "FErFdzAFoA26ASDz9zh4Jan3hV2wRb32Mc1MFMXr7n51", + "Ek7bER9cRJZVHE7Zzmig31PbqT9KkkjAKAgqnyof6JAk", + "EbX6N2wuAAiF6WMnQPG15kq18nx2yApg9ikawxDHBi7j", + "2V9CYburvmC2X2w96HFreUd9iEcW7BdWTFTJCt46tuai", + "AbJpTjriAPp4Vuv5xjoWQHjh68NVSw36Wmky2hQVJJzP", + "F8FqZuUKfoy58aHLW6bfeEhfW9sTtJyqFTqnxVmGZ6dU", + "5hpfC9VBxVcoW9opCnM2PqR6YWRLBzrBpabJTZnwwNiw", + "4XHP9YQeeXPXHAjNXuKio1na1ypcxFSqFYBHtptQticd", + "JDPR4RP95CdtwLcjqe3E4cVthzCmkASfs4yamN9MZyPR", + "CDV3tvd7XwNez9crbEmJpPjdNXceM1Ro5iHqTiaUKt2w", + "6xAckK4UWmaX4CKu27oPzHLxMKzaDMj73WA9xKpqSFQ1", + "9Vfbb8i2Z6WjDJwZEfmhwTk4paCpTYcyJgNFdns2GV2s", + "2UfAKNkmBWjad3qKnFCRfzbHwwhgU5eBs2DDXSJBMVSb", + "9uEDvRyhqygr6SrmvddRDaFbdsazQzuPQCsDewpwfbqh", + "7FdQsXmCW3N5JQbknj3F9Yqq73er9VZJjGhEEMS8Ct2A", + "AoEkWJKHXzrPsgsoawYTLG3aKb9L8oLmVqM9EXFtiPN7", + "7a7iBY13WPKfSpkA1WMpoJB59NE2zr255THWg7GyVb1q", + "7csLUpezHQH7f5uha3s93ruKutcniNQmxjmapRsrfxaR", + "6jFRDDFQDCasLcWVMtixuu1eQCDnMhCttXktVeL7cEYM", + "ATbwzBwGNM8QjLwPGk8PJz8FgCmfWfRud1zB8Zs6tLEb", + "HJbmekvxyMuVjTV2gZKgdBYx94Bumugtt1GrWKBkTv5X", + "AsBeRcytoLArFXwzovGH2gamp9by5B9V1TemMT5LDyQH", + "3pY1zLGNXnQedWwCQeaaHK9dQCsfqMCRPzVD3DnZwSsd", + "29zZdccuHktabvWwJaEokASw6pPBDVpqBDZxTicMhM1R", + "GKD5CK5SqpB66taGqTwGy1FCTyzKrxhyrY7V68aKpoVC", + "Eq9dm4pHewdSVaKdpVJogjLW6upd9hNkiboX2eSncmFV", + "23KfDBTdpaBqfn8aUeoEDgfGJ5368gpnyYGfNkKcECqM", + "5ULtZcyfuWvKuwB555WN4W1vsVW4F3yHU9UW1Gd7kAWy", + "ADBN766ykF4HdkNa7Az8BVrpaQdvSpaMMULufBAs8U1B", + "61YcP8msC5F3ZTLy99VWM2oom6y47UzNmSQQdXMmdCG1", + "984XkyV6X29LUYSi476KC5cTFNMyegrx81EfHj6qWSeV", + "DXu8wVJigvqBLNf18QYQbHn7hcvVWnCpCMoYAPuQGEyr", + "7p1D1WBPr3sK9TYwrRwVcjYwacXhMH3WdJqqyowbvD1f", + "52AXihP4T7dgtfxFMjjLBFVGucNvHmxMW5GkvM1vQyFU", + "HmBHnMwfmsuEFZ4pFpYAXeAkcdnbWzCGEwZ2SXjY8W3N", + "3XSoALqyVbG1ZMgmTwNcuUf294LzjUj7Mvy7MgA7YNVk", + "Gnyw7rZykLq9FjLMzsu6nAryMJijy5FjCEbxxdkymRwk", + "4QJg58aV3UUi2CJ99kiqCMizY81w513qvaQoNgPERHBn", + "FQ2yHp7D3SBYQoe2crFATJdhsazJKJ9Yvq4xFbTzCMYx", + "GSmbMHXC6czx77qXWT3UH1jg2jW6SWdD6D6mFFx3rYmY", + "JDFgtub1sDznJgJRYbHZu1tGQsnhrz17gv8Arq8Zc1SL", + "6BQsUwpVwmPyjGfpE3BAUsNmmbcVy9ygyDYXfpFZ785Z", + "ACthtigKSdBXfCKLUfZNjQzLMmKHzjbSafqpa1NJ3M7J", + "9omg1BYxdA3hhM1rmx3tpMnTf9aqzBRUE9bV6i77b88M", + "HwyjTsHYceVsnhH3Suda9VSqtXftuN9wwjt4aUEx6C3T", + ] + + return rng.random.choice(token_accounts) diff --git a/chainbench/user/protocol/solana.py b/chainbench/user/protocol/solana.py index 4659f8f..765775f 100644 --- a/chainbench/user/protocol/solana.py +++ b/chainbench/user/protocol/solana.py @@ -91,6 +91,9 @@ def _random_account_params_factory(self, rng: RNG) -> list[Account | dict]: {"commitment": "processed"}, ] + def _random_token_account_params_factory(self, rng: RNG) -> list[Account | dict]: + return [self.test_data.get_random_token_account(rng)] + def _get_signature_statuses_params_factory(self, rng: RNG) -> list[list[TxHash] | dict]: return [ [self.test_data.get_random_tx_hash(rng) for _ in range(2, 2 + rng.random.randint(0, 3))], @@ -420,11 +423,10 @@ def get_supply() -> RpcCall: method="getSupply", ) - # TODO: Fix "Invalid param: not a Token account" and "Invalid param: could not find account" errors def get_token_account_balance(self) -> RpcCall: return RpcCall( method="getTokenAccountBalance", - params=self._random_account_params_factory(self.rng.get_rng()), + params=self._random_token_account_params_factory(self.rng.get_rng()), ) def get_token_accounts_by_delegate(self) -> RpcCall: diff --git a/chainbench/util/monitor.py b/chainbench/util/monitor.py index 4098435..88c0aa0 100644 --- a/chainbench/util/monitor.py +++ b/chainbench/util/monitor.py @@ -1,5 +1,6 @@ import csv import logging +import typing from datetime import datetime, timedelta from pathlib import Path from time import sleep @@ -7,6 +8,7 @@ from locust.util.timespan import parse_timespan from orjson import JSONDecodeError +from ..user import SolanaUser from .http import HttpClient logger = logging.getLogger(__name__) @@ -24,30 +26,68 @@ def calculate_lag(current_timestamp: datetime, block_timestamp: datetime) -> int return max(int((current_timestamp - block_timestamp).total_seconds()), 0) -def head_lag_monitor(endpoint: str, result_path: Path, duration: str): - data = { - "id": 1, +# EVM +def eth_get_block_by_number(http_client: HttpClient) -> dict: + body = { "jsonrpc": "2.0", + "id": 1, "method": "eth_getBlockByNumber", "params": ["latest", False], } + response = http_client.post(data=body) + return response.json["result"] + + +# Solana + + +def get_slot(http_client: HttpClient) -> int: + response = http_client.post(data={"jsonrpc": "2.0", "id": 1, "method": "getSlot", "params": []}) + return response.json["result"] + + +def get_block(http_client: HttpClient, slot: int) -> dict: + body = { + "jsonrpc": "2.0", + "id": 1, + "method": "getBlock", + "params": [ + slot, + { + "encoding": "jsonParsed", + "transactionDetails": "none", + "rewards": False, + "maxSupportedTransactionVersion": 0, + }, + ], + } + response = http_client.post(data=body) + return response.json["result"] + + +def sync_lag_monitor(user_class: typing.Any, endpoint: str, result_path: Path, duration: str): end_time = datetime.now() + timedelta(seconds=parse_timespan(duration)) http = HttpClient(endpoint) with open( - file=f"{result_path}/head_lag.csv", + file=f"{result_path}/sync_lag.csv", mode="a", encoding="utf-8-sig", newline="", ) as csv_file: - logger.info("Start monitoring head lag") + logger.info("Start monitoring sync lag") csv_writer = csv.writer(csv_file) csv_writer.writerow(["timestamp", "lag (s)", "block number"]) while datetime.now() < end_time: current_timestamp = datetime.now() - response = http.post(data=data) try: - block_timestamp = datetime.fromtimestamp(int(response.json["result"]["timestamp"], 0)) - block_number = int(response.json["result"]["number"], 0) + if user_class == SolanaUser: + block_number = get_slot(http) + block = get_block(http, block_number) + block_timestamp = datetime.fromtimestamp(block["blockTime"]) + else: + block = eth_get_block_by_number(http) + block_timestamp = datetime.fromtimestamp(int(block["timestamp"], 0)) + block_number = int(block["number"], 0) csv_writer.writerow( [ current_timestamp, @@ -55,12 +95,12 @@ def head_lag_monitor(endpoint: str, result_path: Path, duration: str): block_number, ] ) - logger.info("Written 1 row to head_lag.csv") + logger.info("Written 1 row to sync_lag.csv") sleep(10) except (KeyError, JSONDecodeError): logger.error("Error decoding JSON or key not found") sleep(1) - logger.info("Finished monitoring head lag") + logger.info("Finished monitoring sync lag") -monitors = {"head-lag-monitor": head_lag_monitor} +monitors = {"sync-lag-monitor": sync_lag_monitor}