From e69766fccfee409b51c1da733246b2dcddbc92fc Mon Sep 17 00:00:00 2001 From: huangyi Date: Wed, 18 Sep 2024 12:35:33 +0800 Subject: [PATCH 1/9] Problem: multi-threading tx sending not efficient Solution: - gen txs in advance - use asyncio --- testground/benchmark/benchmark/main.py | 2 +- testground/benchmark/benchmark/peer.py | 21 ++--- testground/benchmark/benchmark/sendtx.py | 68 +++++++++++--- testground/benchmark/benchmark/stateless.py | 23 +++-- .../compositions/docker-compose.jsonnet | 2 +- testground/benchmark/poetry.lock | 89 ++++++++++++++++++- testground/benchmark/pyproject.toml | 1 + 7 files changed, 170 insertions(+), 36 deletions(-) diff --git a/testground/benchmark/benchmark/main.py b/testground/benchmark/benchmark/main.py index 372ad3db4c..ba2ba27d01 100644 --- a/testground/benchmark/benchmark/main.py +++ b/testground/benchmark/benchmark/main.py @@ -36,7 +36,7 @@ def entrypoint(ctx: Context): test_finish_entry = f"finish-test-{ctx.params.test_group_id}" if not ctx.is_validator: - generate_load(cli, ctx.params.num_accounts, ctx.params.num_txs, ctx.global_seq) + generate_load(ctx.params.num_accounts, ctx.params.num_txs, ctx.global_seq) 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/peer.py b/testground/benchmark/benchmark/peer.py index cacc84d9b6..486182e5bc 100644 --- a/testground/benchmark/benchmark/peer.py +++ b/testground/benchmark/benchmark/peer.py @@ -1,3 +1,4 @@ +import itertools import json import tempfile from pathlib import Path @@ -116,16 +117,16 @@ def init_node( def gen_genesis( cli: ChainCommand, leader_home: Path, peers: List[PeerPacket], genesis_patch: dict ): - for peer in peers: - with tempfile.NamedTemporaryFile() as fp: - fp.write(json.dumps(peer.accounts, default=pydantic_encoder).encode()) - fp.flush() - cli( - "genesis", - "bulk-add-genesis-account", - fp.name, - home=leader_home, - ) + accounts = itertools.chain(peer.accounts for peer in peers) + with tempfile.NamedTemporaryFile() as fp: + fp.write(json.dumps(accounts, default=pydantic_encoder).encode()) + fp.flush() + cli( + "genesis", + "bulk-add-genesis-account", + fp.name, + home=leader_home, + ) collect_gen_tx(cli, peers, home=leader_home) cli("genesis", "validate", home=leader_home) return patch_json( diff --git a/testground/benchmark/benchmark/sendtx.py b/testground/benchmark/benchmark/sendtx.py index 8a313e70c9..856e63dc4c 100644 --- a/testground/benchmark/benchmark/sendtx.py +++ b/testground/benchmark/benchmark/sendtx.py @@ -1,12 +1,28 @@ +import asyncio import time from concurrent.futures import ThreadPoolExecutor, as_completed +import aiohttp +import ujson import web3 from eth_account import Account from .utils import gen_account, send_transaction GAS_PRICE = 1000000000 +CHAIN_ID = 777 +LOCAL_JSON_RPC = "http://localhost:8545" + + +def test_tx(nonce: int): + return { + "to": "0x0000000000000000000000000000000000000000", + "value": 1, + "nonce": nonce, + "gas": 21000, + "gasPrice": GAS_PRICE, + "chainId": CHAIN_ID, + } def sendtx(w3: web3.Web3, acct: Account, tx_amount: int): @@ -22,15 +38,8 @@ def sendtx(w3: web3.Web3, acct: Account, tx_amount: int): nonce = initial_nonce while nonce < initial_nonce + tx_amount: - tx = { - "to": "0x0000000000000000000000000000000000000000", - "value": 1, - "nonce": nonce, - "gas": 21000, - "gasPrice": GAS_PRICE, - } try: - send_transaction(w3, tx, acct, wait=False) + send_transaction(test_tx(nonce)) except ValueError as e: msg = str(e) if "invalid nonce" in msg: @@ -55,9 +64,9 @@ def sendtx(w3: web3.Web3, acct: Account, tx_amount: int): ) -def generate_load(cli, num_accounts, num_txs, global_seq, **kwargs): +def generate_load(num_accounts, num_txs, global_seq, **kwargs): w3 = web3.Web3(web3.providers.HTTPProvider("http://localhost:8545")) - assert w3.eth.chain_id == 777 + assert w3.eth.chain_id == CHAIN_ID accounts = [gen_account(global_seq, i + 1) for i in range(num_accounts)] with ThreadPoolExecutor(max_workers=num_accounts) as executor: futs = (executor.submit(sendtx, w3, acct, num_txs) for acct in accounts) @@ -66,3 +75,42 @@ def generate_load(cli, num_accounts, num_txs, global_seq, **kwargs): fut.result() except Exception as e: print("test task failed", e) + + +def prepare_txs(global_seq, num_accounts, num_txs): + accounts = [gen_account(global_seq, i + 1) for i in range(num_accounts)] + txs = [] + for i in range(num_txs): + for acct in accounts: + tx = { + "to": "0x0000000000000000000000000000000000000000", + "value": 1, + "nonce": i, + "gas": 21000, + "gasPrice": GAS_PRICE, + "chainId": CHAIN_ID, + } + txs.append(acct.sign_transaction(tx).rawTransaction.hex()) + return txs + + +async def send_txs(txs): + connector = aiohttp.TCPConnector(limit=None) + async with aiohttp.ClientSession( + connector=connector, json_serialize=ujson.dumps + ) as session: + tasks = [ + asyncio.ensure_future( + session.post( + LOCAL_JSON_RPC, + json={ + "jsonrpc": "2.0", + "method": "eth_sendRawTransaction", + "params": [raw], + "id": 1, + }, + ) + ) + for raw in txs + ] + await asyncio.gather(*tasks) diff --git a/testground/benchmark/benchmark/stateless.py b/testground/benchmark/benchmark/stateless.py index f8c32b817f..0d21076225 100644 --- a/testground/benchmark/benchmark/stateless.py +++ b/testground/benchmark/benchmark/stateless.py @@ -1,3 +1,4 @@ +import asyncio import json import os import shutil @@ -22,11 +23,11 @@ init_node, patch_configs, ) -from .sendtx import generate_load +from .sendtx import prepare_txs, send_txs from .stats import dump_block_stats from .topology import connect_all from .types import PeerPacket -from .utils import block_height, block_txs, wait_for_block, wait_for_port, wait_for_w3 +from .utils import block_height, block_txs, wait_for_block, wait_for_port # use cronosd on host machine LOCAL_CRONOSD_PATH = "cronosd" @@ -206,9 +207,13 @@ def run(outdir: str, datadir: str, cronosd, global_seq): def do_run(home: str, cronosd: str, group: str, global_seq: int, cfg: dict): - run_echo_server(ECHO_SERVER_PORT) + if group == FULLNODE_GROUP or cfg.get("validator-generate-load", True): + txs = prepare_txs(global_seq, cfg["num_accounts"], cfg["num_txs"]) + else: + txs = [] # wait for persistent peers to be ready + run_echo_server(ECHO_SERVER_PORT) wait_for_peers(home) print("start node") @@ -223,16 +228,8 @@ def do_run(home: str, cronosd: str, group: str, global_seq: int, cfg: dict): wait_for_port(8545) wait_for_block(cli, 3) - if group == FULLNODE_GROUP or cfg.get("validator-generate-load", True): - wait_for_w3() - generate_load( - cli, - cfg["num_accounts"], - cfg["num_txs"], - global_seq, - home=home, - output="json", - ) + if txs: + asyncio.run(send_txs(txs)) # node quit when the chain is idle or halted for a while detect_idle_halted(20, 20) diff --git a/testground/benchmark/compositions/docker-compose.jsonnet b/testground/benchmark/compositions/docker-compose.jsonnet index 7589d67497..2624d751e0 100644 --- a/testground/benchmark/compositions/docker-compose.jsonnet +++ b/testground/benchmark/compositions/docker-compose.jsonnet @@ -11,6 +11,6 @@ std.manifestYamlDoc({ JOB_COMPLETION_INDEX: i, }, } - for i in std.range(0, 9) + for i in std.range(0, 3) }, }) diff --git a/testground/benchmark/poetry.lock b/testground/benchmark/poetry.lock index f53b1f83ee..d0e4207cb0 100644 --- a/testground/benchmark/poetry.lock +++ b/testground/benchmark/poetry.lock @@ -1847,6 +1847,93 @@ files = [ {file = "typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"}, ] +[[package]] +name = "ujson" +version = "5.10.0" +description = "Ultra fast JSON encoder and decoder for Python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "ujson-5.10.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2601aa9ecdbee1118a1c2065323bda35e2c5a2cf0797ef4522d485f9d3ef65bd"}, + {file = "ujson-5.10.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:348898dd702fc1c4f1051bc3aacbf894caa0927fe2c53e68679c073375f732cf"}, + {file = "ujson-5.10.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:22cffecf73391e8abd65ef5f4e4dd523162a3399d5e84faa6aebbf9583df86d6"}, + {file = "ujson-5.10.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:26b0e2d2366543c1bb4fbd457446f00b0187a2bddf93148ac2da07a53fe51569"}, + {file = "ujson-5.10.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:caf270c6dba1be7a41125cd1e4fc7ba384bf564650beef0df2dd21a00b7f5770"}, + {file = "ujson-5.10.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:a245d59f2ffe750446292b0094244df163c3dc96b3ce152a2c837a44e7cda9d1"}, + {file = "ujson-5.10.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:94a87f6e151c5f483d7d54ceef83b45d3a9cca7a9cb453dbdbb3f5a6f64033f5"}, + {file = "ujson-5.10.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:29b443c4c0a113bcbb792c88bea67b675c7ca3ca80c3474784e08bba01c18d51"}, + {file = "ujson-5.10.0-cp310-cp310-win32.whl", hash = "sha256:c18610b9ccd2874950faf474692deee4223a994251bc0a083c114671b64e6518"}, + {file = "ujson-5.10.0-cp310-cp310-win_amd64.whl", hash = "sha256:924f7318c31874d6bb44d9ee1900167ca32aa9b69389b98ecbde34c1698a250f"}, + {file = "ujson-5.10.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a5b366812c90e69d0f379a53648be10a5db38f9d4ad212b60af00bd4048d0f00"}, + {file = "ujson-5.10.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:502bf475781e8167f0f9d0e41cd32879d120a524b22358e7f205294224c71126"}, + {file = "ujson-5.10.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5b91b5d0d9d283e085e821651184a647699430705b15bf274c7896f23fe9c9d8"}, + {file = "ujson-5.10.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:129e39af3a6d85b9c26d5577169c21d53821d8cf68e079060602e861c6e5da1b"}, + {file = "ujson-5.10.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f77b74475c462cb8b88680471193064d3e715c7c6074b1c8c412cb526466efe9"}, + {file = "ujson-5.10.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:7ec0ca8c415e81aa4123501fee7f761abf4b7f386aad348501a26940beb1860f"}, + {file = "ujson-5.10.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:ab13a2a9e0b2865a6c6db9271f4b46af1c7476bfd51af1f64585e919b7c07fd4"}, + {file = "ujson-5.10.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:57aaf98b92d72fc70886b5a0e1a1ca52c2320377360341715dd3933a18e827b1"}, + {file = "ujson-5.10.0-cp311-cp311-win32.whl", hash = "sha256:2987713a490ceb27edff77fb184ed09acdc565db700ee852823c3dc3cffe455f"}, + {file = "ujson-5.10.0-cp311-cp311-win_amd64.whl", hash = "sha256:f00ea7e00447918ee0eff2422c4add4c5752b1b60e88fcb3c067d4a21049a720"}, + {file = "ujson-5.10.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:98ba15d8cbc481ce55695beee9f063189dce91a4b08bc1d03e7f0152cd4bbdd5"}, + {file = "ujson-5.10.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a9d2edbf1556e4f56e50fab7d8ff993dbad7f54bac68eacdd27a8f55f433578e"}, + {file = "ujson-5.10.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6627029ae4f52d0e1a2451768c2c37c0c814ffc04f796eb36244cf16b8e57043"}, + {file = "ujson-5.10.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f8ccb77b3e40b151e20519c6ae6d89bfe3f4c14e8e210d910287f778368bb3d1"}, + {file = "ujson-5.10.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f3caf9cd64abfeb11a3b661329085c5e167abbe15256b3b68cb5d914ba7396f3"}, + {file = "ujson-5.10.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6e32abdce572e3a8c3d02c886c704a38a1b015a1fb858004e03d20ca7cecbb21"}, + {file = "ujson-5.10.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:a65b6af4d903103ee7b6f4f5b85f1bfd0c90ba4eeac6421aae436c9988aa64a2"}, + {file = "ujson-5.10.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:604a046d966457b6cdcacc5aa2ec5314f0e8c42bae52842c1e6fa02ea4bda42e"}, + {file = "ujson-5.10.0-cp312-cp312-win32.whl", hash = "sha256:6dea1c8b4fc921bf78a8ff00bbd2bfe166345f5536c510671bccececb187c80e"}, + {file = "ujson-5.10.0-cp312-cp312-win_amd64.whl", hash = "sha256:38665e7d8290188b1e0d57d584eb8110951a9591363316dd41cf8686ab1d0abc"}, + {file = "ujson-5.10.0-cp313-cp313-macosx_10_9_x86_64.whl", hash = "sha256:618efd84dc1acbd6bff8eaa736bb6c074bfa8b8a98f55b61c38d4ca2c1f7f287"}, + {file = "ujson-5.10.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:38d5d36b4aedfe81dfe251f76c0467399d575d1395a1755de391e58985ab1c2e"}, + {file = "ujson-5.10.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:67079b1f9fb29ed9a2914acf4ef6c02844b3153913eb735d4bf287ee1db6e557"}, + {file = "ujson-5.10.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d7d0e0ceeb8fe2468c70ec0c37b439dd554e2aa539a8a56365fd761edb418988"}, + {file = "ujson-5.10.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:59e02cd37bc7c44d587a0ba45347cc815fb7a5fe48de16bf05caa5f7d0d2e816"}, + {file = "ujson-5.10.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:2a890b706b64e0065f02577bf6d8ca3b66c11a5e81fb75d757233a38c07a1f20"}, + {file = "ujson-5.10.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:621e34b4632c740ecb491efc7f1fcb4f74b48ddb55e65221995e74e2d00bbff0"}, + {file = "ujson-5.10.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:b9500e61fce0cfc86168b248104e954fead61f9be213087153d272e817ec7b4f"}, + {file = "ujson-5.10.0-cp313-cp313-win32.whl", hash = "sha256:4c4fc16f11ac1612f05b6f5781b384716719547e142cfd67b65d035bd85af165"}, + {file = "ujson-5.10.0-cp313-cp313-win_amd64.whl", hash = "sha256:4573fd1695932d4f619928fd09d5d03d917274381649ade4328091ceca175539"}, + {file = "ujson-5.10.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:a984a3131da7f07563057db1c3020b1350a3e27a8ec46ccbfbf21e5928a43050"}, + {file = "ujson-5.10.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:73814cd1b9db6fc3270e9d8fe3b19f9f89e78ee9d71e8bd6c9a626aeaeaf16bd"}, + {file = "ujson-5.10.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:61e1591ed9376e5eddda202ec229eddc56c612b61ac6ad07f96b91460bb6c2fb"}, + {file = "ujson-5.10.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2c75269f8205b2690db4572a4a36fe47cd1338e4368bc73a7a0e48789e2e35a"}, + {file = "ujson-5.10.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7223f41e5bf1f919cd8d073e35b229295aa8e0f7b5de07ed1c8fddac63a6bc5d"}, + {file = "ujson-5.10.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:d4dc2fd6b3067c0782e7002ac3b38cf48608ee6366ff176bbd02cf969c9c20fe"}, + {file = "ujson-5.10.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:232cc85f8ee3c454c115455195a205074a56ff42608fd6b942aa4c378ac14dd7"}, + {file = "ujson-5.10.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:cc6139531f13148055d691e442e4bc6601f6dba1e6d521b1585d4788ab0bfad4"}, + {file = "ujson-5.10.0-cp38-cp38-win32.whl", hash = "sha256:e7ce306a42b6b93ca47ac4a3b96683ca554f6d35dd8adc5acfcd55096c8dfcb8"}, + {file = "ujson-5.10.0-cp38-cp38-win_amd64.whl", hash = "sha256:e82d4bb2138ab05e18f089a83b6564fee28048771eb63cdecf4b9b549de8a2cc"}, + {file = "ujson-5.10.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:dfef2814c6b3291c3c5f10065f745a1307d86019dbd7ea50e83504950136ed5b"}, + {file = "ujson-5.10.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4734ee0745d5928d0ba3a213647f1c4a74a2a28edc6d27b2d6d5bd9fa4319e27"}, + {file = "ujson-5.10.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d47ebb01bd865fdea43da56254a3930a413f0c5590372a1241514abae8aa7c76"}, + {file = "ujson-5.10.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dee5e97c2496874acbf1d3e37b521dd1f307349ed955e62d1d2f05382bc36dd5"}, + {file = "ujson-5.10.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7490655a2272a2d0b072ef16b0b58ee462f4973a8f6bbe64917ce5e0a256f9c0"}, + {file = "ujson-5.10.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:ba17799fcddaddf5c1f75a4ba3fd6441f6a4f1e9173f8a786b42450851bd74f1"}, + {file = "ujson-5.10.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:2aff2985cef314f21d0fecc56027505804bc78802c0121343874741650a4d3d1"}, + {file = "ujson-5.10.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:ad88ac75c432674d05b61184178635d44901eb749786c8eb08c102330e6e8996"}, + {file = "ujson-5.10.0-cp39-cp39-win32.whl", hash = "sha256:2544912a71da4ff8c4f7ab5606f947d7299971bdd25a45e008e467ca638d13c9"}, + {file = "ujson-5.10.0-cp39-cp39-win_amd64.whl", hash = "sha256:3ff201d62b1b177a46f113bb43ad300b424b7847f9c5d38b1b4ad8f75d4a282a"}, + {file = "ujson-5.10.0-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:5b6fee72fa77dc172a28f21693f64d93166534c263adb3f96c413ccc85ef6e64"}, + {file = "ujson-5.10.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:61d0af13a9af01d9f26d2331ce49bb5ac1fb9c814964018ac8df605b5422dcb3"}, + {file = "ujson-5.10.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ecb24f0bdd899d368b715c9e6664166cf694d1e57be73f17759573a6986dd95a"}, + {file = "ujson-5.10.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fbd8fd427f57a03cff3ad6574b5e299131585d9727c8c366da4624a9069ed746"}, + {file = "ujson-5.10.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:beeaf1c48e32f07d8820c705ff8e645f8afa690cca1544adba4ebfa067efdc88"}, + {file = "ujson-5.10.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:baed37ea46d756aca2955e99525cc02d9181de67f25515c468856c38d52b5f3b"}, + {file = "ujson-5.10.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:7663960f08cd5a2bb152f5ee3992e1af7690a64c0e26d31ba7b3ff5b2ee66337"}, + {file = "ujson-5.10.0-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:d8640fb4072d36b08e95a3a380ba65779d356b2fee8696afeb7794cf0902d0a1"}, + {file = "ujson-5.10.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:78778a3aa7aafb11e7ddca4e29f46bc5139131037ad628cc10936764282d6753"}, + {file = "ujson-5.10.0-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b0111b27f2d5c820e7f2dbad7d48e3338c824e7ac4d2a12da3dc6061cc39c8e6"}, + {file = "ujson-5.10.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:c66962ca7565605b355a9ed478292da628b8f18c0f2793021ca4425abf8b01e5"}, + {file = "ujson-5.10.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:ba43cc34cce49cf2d4bc76401a754a81202d8aa926d0e2b79f0ee258cb15d3a4"}, + {file = "ujson-5.10.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:ac56eb983edce27e7f51d05bc8dd820586c6e6be1c5216a6809b0c668bb312b8"}, + {file = "ujson-5.10.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f44bd4b23a0e723bf8b10628288c2c7c335161d6840013d4d5de20e48551773b"}, + {file = "ujson-5.10.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7c10f4654e5326ec14a46bcdeb2b685d4ada6911050aa8baaf3501e57024b804"}, + {file = "ujson-5.10.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0de4971a89a762398006e844ae394bd46991f7c385d7a6a3b93ba229e6dac17e"}, + {file = "ujson-5.10.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:e1402f0564a97d2a52310ae10a64d25bcef94f8dd643fcf5d310219d915484f7"}, + {file = "ujson-5.10.0.tar.gz", hash = "sha256:b3cd8f3c5d8c7738257f1018880444f7b7d9b66232c64649f562d7ba86ad4bc1"}, +] + [[package]] name = "urllib3" version = "2.2.2" @@ -2101,4 +2188,4 @@ multidict = ">=4.0" [metadata] lock-version = "2.0" python-versions = "^3.11" -content-hash = "58618047dc3ced34b3e62b0115fa8b419d82b4f81357055905e4abc5bbd5e71c" +content-hash = "f95059b65ce788a6cef6d06ec8d9dd9e65a819502003b2c3fa269647c0bc299d" diff --git a/testground/benchmark/pyproject.toml b/testground/benchmark/pyproject.toml index d19f457cd6..e626b7f291 100644 --- a/testground/benchmark/pyproject.toml +++ b/testground/benchmark/pyproject.toml @@ -16,6 +16,7 @@ hexbytes = "^0" bech32 = "^1" requests = "^2.32" click = "^8.1.7" +ujson = "^5.10.0" [tool.poetry.dev-dependencies] pytest = "^8.2" From cdc7c8b211eb640d569aab327eae4a3708bd5928 Mon Sep 17 00:00:00 2001 From: yihuang Date: Wed, 18 Sep 2024 13:04:30 +0800 Subject: [PATCH 2/9] Update testground/benchmark/compositions/docker-compose.jsonnet Signed-off-by: yihuang --- 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 2624d751e0..7589d67497 100644 --- a/testground/benchmark/compositions/docker-compose.jsonnet +++ b/testground/benchmark/compositions/docker-compose.jsonnet @@ -11,6 +11,6 @@ std.manifestYamlDoc({ JOB_COMPLETION_INDEX: i, }, } - for i in std.range(0, 3) + for i in std.range(0, 9) }, }) From 779735799211ff17036721b4bc33aa032c3cd730 Mon Sep 17 00:00:00 2001 From: yihuang Date: Wed, 18 Sep 2024 13:06:16 +0800 Subject: [PATCH 3/9] Update testground/benchmark/benchmark/sendtx.py Signed-off-by: yihuang --- testground/benchmark/benchmark/sendtx.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testground/benchmark/benchmark/sendtx.py b/testground/benchmark/benchmark/sendtx.py index 856e63dc4c..a102b66b25 100644 --- a/testground/benchmark/benchmark/sendtx.py +++ b/testground/benchmark/benchmark/sendtx.py @@ -39,7 +39,7 @@ def sendtx(w3: web3.Web3, acct: Account, tx_amount: int): nonce = initial_nonce while nonce < initial_nonce + tx_amount: try: - send_transaction(test_tx(nonce)) + send_transaction(w3, test_tx(nonce), acct, wait=False) except ValueError as e: msg = str(e) if "invalid nonce" in msg: From 09ab9fd1dbf3aac7be964f22a7ea2ed3e84dc28a Mon Sep 17 00:00:00 2001 From: yihuang Date: Wed, 18 Sep 2024 13:09:12 +0800 Subject: [PATCH 4/9] Update testground/benchmark/benchmark/sendtx.py Signed-off-by: yihuang --- testground/benchmark/benchmark/sendtx.py | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/testground/benchmark/benchmark/sendtx.py b/testground/benchmark/benchmark/sendtx.py index a102b66b25..69d1d67520 100644 --- a/testground/benchmark/benchmark/sendtx.py +++ b/testground/benchmark/benchmark/sendtx.py @@ -82,15 +82,7 @@ def prepare_txs(global_seq, num_accounts, num_txs): txs = [] for i in range(num_txs): for acct in accounts: - tx = { - "to": "0x0000000000000000000000000000000000000000", - "value": 1, - "nonce": i, - "gas": 21000, - "gasPrice": GAS_PRICE, - "chainId": CHAIN_ID, - } - txs.append(acct.sign_transaction(tx).rawTransaction.hex()) + txs.append(acct.sign_transaction(test_tx(i)).rawTransaction.hex()) return txs From 27fa295743377cfa9d6a1525fe9ffcf04d47e589 Mon Sep 17 00:00:00 2001 From: huangyi Date: Wed, 18 Sep 2024 14:09:48 +0800 Subject: [PATCH 5/9] fix tps --- testground/benchmark/benchmark/stats.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/testground/benchmark/benchmark/stats.py b/testground/benchmark/benchmark/stats.py index e4b1d5d15f..1a0978179c 100644 --- a/testground/benchmark/benchmark/stats.py +++ b/testground/benchmark/benchmark/stats.py @@ -3,14 +3,14 @@ from .utils import block, block_height # the tps calculation use the average of the last 10 blocks -TPS_WINDOW = 10 +TPS_WINDOW = 5 def calculate_tps(blocks): if len(blocks) < 2: return 0 - txs = sum(n for n, _ in blocks) + txs = sum(n for n, _ in blocks[1:]) _, t1 = blocks[0] _, t2 = blocks[-1] time_diff = (t2 - t1).total_seconds() From e09e326f7a23677f52ee399d69632c97d28c3b58 Mon Sep 17 00:00:00 2001 From: huangyi Date: Wed, 18 Sep 2024 14:11:29 +0800 Subject: [PATCH 6/9] add logs --- testground/benchmark/benchmark/peer.py | 2 ++ testground/benchmark/benchmark/sendtx.py | 3 +++ testground/benchmark/benchmark/stateless.py | 1 + 3 files changed, 6 insertions(+) diff --git a/testground/benchmark/benchmark/peer.py b/testground/benchmark/benchmark/peer.py index 486182e5bc..faddfa8bc3 100644 --- a/testground/benchmark/benchmark/peer.py +++ b/testground/benchmark/benchmark/peer.py @@ -118,6 +118,7 @@ def gen_genesis( cli: ChainCommand, leader_home: Path, peers: List[PeerPacket], genesis_patch: dict ): accounts = itertools.chain(peer.accounts for peer in peers) + print("adding genesis accounts", len(accounts)) with tempfile.NamedTemporaryFile() as fp: fp.write(json.dumps(accounts, default=pydantic_encoder).encode()) fp.flush() @@ -129,6 +130,7 @@ def gen_genesis( ) collect_gen_tx(cli, peers, home=leader_home) cli("genesis", "validate", home=leader_home) + print("genesis validated") return patch_json( leader_home / "config" / "genesis.json", { diff --git a/testground/benchmark/benchmark/sendtx.py b/testground/benchmark/benchmark/sendtx.py index 69d1d67520..8a5c5b6949 100644 --- a/testground/benchmark/benchmark/sendtx.py +++ b/testground/benchmark/benchmark/sendtx.py @@ -83,6 +83,9 @@ def prepare_txs(global_seq, num_accounts, num_txs): for i in range(num_txs): for acct in accounts: txs.append(acct.sign_transaction(test_tx(i)).rawTransaction.hex()) + if len(txs) % 1000 == 0: + print("prepared", len(txs), "txs") + return txs diff --git a/testground/benchmark/benchmark/stateless.py b/testground/benchmark/benchmark/stateless.py index 0d21076225..063a59e4ef 100644 --- a/testground/benchmark/benchmark/stateless.py +++ b/testground/benchmark/benchmark/stateless.py @@ -208,6 +208,7 @@ def run(outdir: str, datadir: str, cronosd, global_seq): def do_run(home: str, cronosd: str, group: str, global_seq: int, cfg: dict): if group == FULLNODE_GROUP or cfg.get("validator-generate-load", True): + print("preparing", cfg["num_accounts"] * cfg["num_txs"], "txs") txs = prepare_txs(global_seq, cfg["num_accounts"], cfg["num_txs"]) else: txs = [] From 1e299dd1a48df721bc8904c6d85823aede10987d Mon Sep 17 00:00:00 2001 From: huangyi Date: Wed, 18 Sep 2024 14:40:09 +0800 Subject: [PATCH 7/9] fix --- 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 faddfa8bc3..f8b043b758 100644 --- a/testground/benchmark/benchmark/peer.py +++ b/testground/benchmark/benchmark/peer.py @@ -117,7 +117,7 @@ def init_node( def gen_genesis( cli: ChainCommand, leader_home: Path, peers: List[PeerPacket], genesis_patch: dict ): - accounts = itertools.chain(peer.accounts for peer in peers) + accounts = list(itertools.chain(*(peer.accounts for peer in peers))) print("adding genesis accounts", len(accounts)) with tempfile.NamedTemporaryFile() as fp: fp.write(json.dumps(accounts, default=pydantic_encoder).encode()) From 222429992a52c5eae52c19ae12bbc5f3b3e00f4c Mon Sep 17 00:00:00 2001 From: huangyi Date: Wed, 18 Sep 2024 15:01:18 +0800 Subject: [PATCH 8/9] limit connection pool size --- testground/benchmark/benchmark/sendtx.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/testground/benchmark/benchmark/sendtx.py b/testground/benchmark/benchmark/sendtx.py index 8a5c5b6949..7f3439c59f 100644 --- a/testground/benchmark/benchmark/sendtx.py +++ b/testground/benchmark/benchmark/sendtx.py @@ -12,6 +12,7 @@ GAS_PRICE = 1000000000 CHAIN_ID = 777 LOCAL_JSON_RPC = "http://localhost:8545" +CONNECTION_POOL_SIZE = 1024 def test_tx(nonce: int): @@ -90,7 +91,7 @@ def prepare_txs(global_seq, num_accounts, num_txs): async def send_txs(txs): - connector = aiohttp.TCPConnector(limit=None) + connector = aiohttp.TCPConnector(limit=1024) async with aiohttp.ClientSession( connector=connector, json_serialize=ujson.dumps ) as session: From 421059aad1b84db4c5b87338ce7061a7f59df77d Mon Sep 17 00:00:00 2001 From: huangyi Date: Wed, 18 Sep 2024 15:15:11 +0800 Subject: [PATCH 9/9] error message --- testground/benchmark/benchmark/sendtx.py | 30 +++++++++++++----------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/testground/benchmark/benchmark/sendtx.py b/testground/benchmark/benchmark/sendtx.py index 7f3439c59f..22a1bd6740 100644 --- a/testground/benchmark/benchmark/sendtx.py +++ b/testground/benchmark/benchmark/sendtx.py @@ -90,23 +90,25 @@ def prepare_txs(global_seq, num_accounts, num_txs): return txs +async def async_sendtx(session, raw): + async with session.post( + LOCAL_JSON_RPC, + json={ + "jsonrpc": "2.0", + "method": "eth_sendRawTransaction", + "params": [raw], + "id": 1, + }, + ) as rsp: + data = await rsp.json() + if "error" in data: + print("send tx error", data["error"]) + + async def send_txs(txs): connector = aiohttp.TCPConnector(limit=1024) async with aiohttp.ClientSession( connector=connector, json_serialize=ujson.dumps ) as session: - tasks = [ - asyncio.ensure_future( - session.post( - LOCAL_JSON_RPC, - json={ - "jsonrpc": "2.0", - "method": "eth_sendRawTransaction", - "params": [raw], - "id": 1, - }, - ) - ) - for raw in txs - ] + tasks = [asyncio.ensure_future(async_sendtx(session, raw)) for raw in txs] await asyncio.gather(*tasks)