-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Str-998: Implement different transaction types for the load testing. (#…
…658) * Minor fixes. * Add EthTransaction load job. * Prettify: add structured logging and some comments/docstrings. * Better logging. * Fix lints and codespell. * Disable basic_load test for now. * Allow waiting for confirmation of SC calls. Also, formatting of solidity code.
- Loading branch information
1 parent
1e2b41a
commit ed8d602
Showing
19 changed files
with
869 additions
and
123 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,65 +1,40 @@ | ||
import web3 | ||
import web3.middleware | ||
from locust import HttpUser | ||
|
||
from utils import setup_load_job_logger | ||
|
||
|
||
class StrataLoadJob(HttpUser): | ||
""" | ||
A common layer for all the load jobs in the load tests. | ||
""" | ||
|
||
pass | ||
def on_start(self): | ||
super().on_start() | ||
|
||
# Setup a separate logger with its own file for each load job. | ||
self._logger = setup_load_job_logger(self.environment._datadir, type(self).__name__) | ||
|
||
# TODO(load): configure the structured logging as we do in the tests. | ||
class BaseRethLoadJob(StrataLoadJob): | ||
fund_amount: int = 1_000_000_000_000_000_000_000 # 1000 ETH | ||
# Technically, before_start and after_start can be merged. | ||
# It's done to separate initialization logic (aka constructor) from "run-it-once" logic. | ||
# Also, with that in mind, the "on_start" is a bit misleading. | ||
self._logger.info("Before start:") | ||
self.before_start() | ||
self._logger.info("Before start completed.") | ||
|
||
def on_start(self): | ||
root_w3, genesis_acc = self.w3_with_genesis_acc() | ||
self._root_w3 = root_w3 | ||
self._genesis_acc = genesis_acc | ||
self._logger.info("After start:") | ||
self.after_start() | ||
self._logger.info("After start completed.") | ||
|
||
def w3_with_genesis_acc(self): | ||
def before_start(self): | ||
""" | ||
Return w3 with prefunded "root" account as specified in the chain config. | ||
Called right before a job starts running. | ||
A good place for the subclass to initialize the state. | ||
""" | ||
return self._init_w3( | ||
lambda w3: w3.eth.account.from_key( | ||
"0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80" | ||
) | ||
) | ||
pass | ||
|
||
def w3_with_new_acc(self): | ||
def after_start(self): | ||
""" | ||
Return w3 with a fresh account. | ||
Also, funds this account, so it's able to sign and send some txns. | ||
Called right before a job starts running, but after `before_start`. | ||
A good place for the subclass to perform some actions once (before the job actually starts). | ||
""" | ||
w3, new_acc = self._init_w3(lambda w3: w3.eth.account.create()) | ||
self._fund_account(new_acc.address) | ||
|
||
return w3, new_acc | ||
|
||
def _init_w3(self, init): | ||
# Reuse the http session by locust internals, so the stats are measured correctly. | ||
w3 = web3.Web3(web3.Web3.HTTPProvider(self.host, session=self.client)) | ||
# Init the account according to lambda | ||
account = init(w3) | ||
# Set the account onto web3 and init the signing middleware. | ||
w3.address = account.address | ||
w3.middleware_onion.add(web3.middleware.SignAndSendRawMiddlewareBuilder.build(account)) | ||
|
||
return w3, account | ||
|
||
def _fund_account(self, acc): | ||
print(f"FUNDING ACCOUNT {acc}") | ||
source = self._root_w3.address | ||
tx_hash = self._root_w3.eth.send_transaction( | ||
{"to": acc, "value": hex(self.fund_amount), "gas": hex(100000), "from": source} | ||
) | ||
|
||
tx_receipt = self._root_w3.eth.wait_for_transaction_receipt(tx_hash, timeout=120) | ||
print(f"FUNDING SUCCESS: {tx_receipt}") | ||
|
||
def _balance(self, acc): | ||
return self._root_w3.eth.get_balance(acc) | ||
pass |
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
from .jobs import * |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,120 @@ | ||
import web3 | ||
from gevent.lock import Semaphore | ||
from web3.middleware.signing import SignAndSendRawMiddlewareBuilder | ||
|
||
from load.job import StrataLoadJob | ||
|
||
|
||
class AbstractAccount: | ||
""" | ||
Abstract Ethereum-like account on RETH in fntests. | ||
""" | ||
|
||
_nonce: int = 0 | ||
""" | ||
Nonce of the account w3 is initialized with. | ||
""" | ||
|
||
_nonce_lock = Semaphore() | ||
""" | ||
Gevent synchronization primitive on the nonce. | ||
The reason is twofold: | ||
- to avoid fetching the current nonce before each transaction. | ||
- to avoid races on the nonce when different green threads use the same account. | ||
""" | ||
|
||
@property | ||
def w3(self) -> web3.Web3: | ||
raise NotImplementedError("w3 should be implemented by subclasses") | ||
|
||
@property | ||
def account(self): | ||
raise NotImplementedError("account should be implemented by subclasses") | ||
|
||
@property | ||
def nonce(self): | ||
with self._nonce_lock: | ||
nonce = self._nonce | ||
self._nonce += 1 | ||
return nonce | ||
|
||
@property | ||
def address(self): | ||
return self.account.address | ||
|
||
@property | ||
def balance(self): | ||
return self.w3.eth.account.get_balance(self.address) | ||
|
||
|
||
class GenesisAccount: | ||
""" | ||
Prefunded account according to the genesis config of RETH in fntests. | ||
""" | ||
|
||
nonce: int = 0 | ||
nonce_lock = Semaphore() | ||
|
||
def __init__(self, job: StrataLoadJob): | ||
w3 = web3.Web3(web3.Web3.HTTPProvider(job.host, session=job.client)) | ||
# Init the prefunded account as specified in the chain config. | ||
account = w3.eth.account.from_key( | ||
"0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80" | ||
) | ||
# Set the account onto web3 and init the signing middleware. | ||
w3.address = account.address | ||
w3.middleware_onion.add(SignAndSendRawMiddlewareBuilder.build(account)) | ||
self._w3 = w3 | ||
self._account = account | ||
|
||
def fund_address(self, account_address, amount) -> bool: | ||
# We use class attribute here (rather than object attribute) to have | ||
# the same nonce lock even if multiple instances of GenesisAccount are used. | ||
nonce = GenesisAccount._inc_nonce() | ||
tx_hash = self._w3.eth.send_transaction( | ||
{ | ||
"to": account_address, | ||
"value": hex(amount), | ||
"gas": hex(100000), | ||
"from": self._account.address, | ||
"nonce": nonce, | ||
} | ||
) | ||
|
||
# Block on this transaction to make sure funding is successful before proceeding further. | ||
tx_receipt = self._w3.eth.wait_for_transaction_receipt(tx_hash, timeout=120) | ||
return tx_receipt["status"] == 1 | ||
|
||
@classmethod | ||
def _inc_nonce(cls): | ||
with cls.nonce_lock: | ||
nonce = cls.nonce | ||
cls.nonce += 1 | ||
return nonce | ||
|
||
|
||
class FundedAccount(AbstractAccount): | ||
""" | ||
Fresh Ethereum-like account with no funds. | ||
""" | ||
|
||
def __init__(self, job: StrataLoadJob): | ||
w3 = web3.Web3(web3.Web3.HTTPProvider(job.host, session=job.client)) | ||
# Init the new account. | ||
account = w3.eth.account.create() | ||
# Set the account onto web3 and init the signing middleware. | ||
w3.address = account.address | ||
w3.middleware_onion.add(SignAndSendRawMiddlewareBuilder.build(account)) | ||
self._w3 = w3 | ||
self._account = account | ||
|
||
def fund_me(self, genesis_acc: GenesisAccount, amount=1_000_000_000_000_000_000_000): | ||
genesis_acc.fund_address(self.address, amount) | ||
|
||
@property | ||
def w3(self): | ||
return self._w3 | ||
|
||
@property | ||
def account(self): | ||
return self._account |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity ^0.8.0; | ||
|
||
contract Counter { | ||
uint256 private count; | ||
|
||
event CounterIncremented(uint256 newValue); | ||
event CounterDecremented(uint256 newValue); | ||
|
||
function increment() public { | ||
count += 1; | ||
emit CounterIncremented(count); | ||
} | ||
|
||
function decrement() public { | ||
require(count > 0, "Counter cannot be negative"); | ||
count -= 1; | ||
emit CounterDecremented(count); | ||
} | ||
|
||
function getCount() public view returns (uint256) { | ||
return count; | ||
} | ||
} |
Oops, something went wrong.