Skip to content

Conversation

CPerezz and others added 30 commits May 7, 2025 16:45
Includes the scenarios contemplated within statebloat as well as any
extra data about them such as gas cost metrics.
This scenario deploys contracts that are exactly 24kB in size (EIP-170 limit) to maximize state growth while minimizing gas cost.

1. Generates a contract with exactly 24,576 bytes of runtime code
2. Deploys the contract using CREATE
3. Each deployment adds:
   - 24,576 bytes of runtime code
   - Account trie node
   - Total state growth: ~24.7kB per deployment

- 32,000 gas for CREATE
- 20,000 gas for new account
- 200 gas per byte for code deposit (24,576 bytes)
- Total: 4,967,200 gas per deployment
- Remove redundant throughput flag and consolidate to contracts-per-tx
- Remove count flag and related code for cleaner interface
- Update wallet count calculation to use contracts-per-tx
- Keep only two deployment rate control methods:
  - contracts-per-tx: direct control of contracts per transaction
  - gas-per-block: calculate contracts based on target gas

The scenario now runs indefinitely until stopped, with cleaner and more
focused configuration options.
- Add validation to ensure contract deployments don't exceed block gas limit
- Check both gas-per-block and contracts-per-tx against block gas limit
- Add clear error messages when gas limits are exceeded
- Move validation to Run() function to access context
- Introduce multiple test cases for contract deployment: using contracts per block, gas per block, and handling invalid configurations.
- Update config opts to replace `contracts-per-tx` with `contracts-per-block` for better clarity.
- Add error handling for scenarios where neither gas per block nor contracts per block is set.
- Refactor gas fee parameters to align with EIP-1559 standards.
- Initialize wallet pool in the contract deployment test.
- Introduced setup and teardown for contract deployment tests.
- Updated scenario options to include a maximum transactions limit. St we can test for a single tx at a time and shortening testing time.
…to max (EIP170)

- Introduced multiple dummy functions in the StateBloatToken contract to artificially inflate bytecode size.
- Updated ABI and binary files to reflect changes in the contract structure.
- Updated the contract deployment scenario to log deployed contract addresses and gas used.
- Added functionality to write deployed addresses to a JSON file for easier tracking.
- Removed gas-per-block validation and adjusted wallet count logic.
- Improved README with instructions for running against a local Anvil node without Go tests.
…ction tracking

- Introduced a batch deployment strategy that calculates the number of contracts fitting within the block gas limit.
- Added detailed tracking for deployed contracts, including gas used and bytecode size, with structured loggin.
- Improved nonce management and transaction retry logic.
… logging

- Added functionality to save a mapping of private keys to contract addresses in a deployments.json file after each contract deployment.
- Refactored the final summary logging to focus on the deployments.json file, removing the previous detailed contract saving logic.
- imporved logging to provide insights into the total number of deployers and contracts processed.
…mprove transaction handling

- Removed unused imports and redundant fields.
- Simplified transaction processing by releasing locks earlier.
- Improved logging for transaction sending and contract deployment confirmation.
- Cleaned up nonce management by directly fetching the nonce from the client.
…djustment

- Added functionality to dynamically adjust transaction fees based on current network conditions.
- Implemented retry logic for transaction sending with exponential backoff for base fee errors.
…s_limit

- Introduced BlockDeploymentStats struct to track deployment statistics per block, including contract count, total gas used, and total bytecode size.
- Implemented real-time block monitoring for logging deployment summaries.
- Updated contract bytecode size calculations to reflect actual deployed bytecode.
- Adjusted transaction processing intervals for improved efficiency.
Revert the changes done to the original `setcodetx`.
- Move the bloating code to `eoa-delegation` under statebloat.
…ario for state bloat testing

The idea is that it performs the maximum amount of SSTORE possible with the available gas limit within a single tx execution that consumes it all.
…mentation

The scenario uses deployed StateBloatToken contracts from `deployments.json` to send the maximum possible number of ERC20 transfers per block. Each transfer sends 1 token to a unique, never-before-used address, maximizing state growth.
Signed-off-by: CPerezz <37264926+CPerezz@users.noreply.github.com>
Signed-off-by: CPerezz <37264926+CPerezz@users.noreply.github.com>
Signed-off-by: CPerezz <37264926+CPerezz@users.noreply.github.com>
Signed-off-by: CPerezz <37264926+CPerezz@users.noreply.github.com>
@CPerezz
Copy link
Contributor

CPerezz commented Jun 19, 2025

Hey @pk910! Thanks for this! But I hink we should be good with the PRs I made (splited the original one as we agreed upon).

If we merge in order I think we should be fine. LMK if there's any issue

@pk910
Copy link
Member Author

pk910 commented Jun 19, 2025

Heya @CPerezz,
There are unfortunately various issues with the PRs :/
It's still based on a very old master state, so merging will not work due to changed Types.
It's also not following some important patterns of spamoor:

  1. you're using the root wallet way too much. This seems simple on first glance, but it breaks spamoor when using it with multiple concurrently executed scenarios, as the root wallet is shared across all of them and may not have nonce gaps or too many pending transactions.
    You also have limits on the number of pending transactions from various clients. Exceeding that limit will lead to dropped txs and therefore nonce gaps. That's why we have that whole logic to send thousands of transactions via multiple sender wallets - so the pending tx count per wallet never exceeds the limit.

  2. There are various issues arising by switching to the go-ethereum contract binding system midway through.
    This won't work as the nonces that are internally used by the binding subsystem are not tracked by spamoor, which leads to reusing them again in different situations. This especially gets worse as you're also using the root wallet directly for this.

I'm currently going through the code and trying to clean it up a bit. But at the end I'm still not sure about what it is needed for? :D

It seems like these state growth scenarios are all way slower than the existing complementary scenarios as you have that split funding / bloating & analyze phases looped through.
I kinda get it for the eoa-delegation scenario, as there is a small logical difference compared to the setcodetx scenario by funding the delegators with 1wei each.
(Btw, why is this needed? And is it strictly necessary as a pre-step before doing the delegation?)

But I don't really get the diff for rand_sstore vs storagespam and erc20-max-transfers vs erctx?
Is it just because you need to generate the summary at the end?

The erc20 scenario also misses the contracts to deploy, which makes the scenario quite hard to use as you need the prerequisites (deployments file, and the contracts to deploy) from somewhere?

@CPerezz
Copy link
Contributor

CPerezz commented Jun 19, 2025

It's still based on a very old master state, so merging will not work due to changed Types.

I didn't realize. Will update that myself. No worries.

you're using the root wallet way too much. This seems simple on first glance, but it breaks spamoor when using it with multiple concurrently executed scenarios, as the root wallet is shared across all of them and may not have nonce gaps or too many pending transactions.
Yes, and one of my assumptions was always why isn't the nonce behind a Mutex or something similar. Though now that you mention it, I agree that if there are multiple instances running in different contexts. Then this breaks even with Mutex.

I can definitely change that no worries!

You also have limits on the number of pending transactions from various clients. Exceeding that limit will lead to dropped txs and therefore nonce gaps. That's why we have that whole logic to send thousands of transactions via multiple sender wallets - so the pending tx count per wallet never exceeds the limit.

I ignored this. That's good to know. And perfectly explains why we should avoid the RootWallet usage. (Most of my scenarios are rate-limited anyways) but agree with you we should change it.

There are various issues arising by switching to the go-ethereum contract binding system midway through.
This won't work as the nonces that are internally used by the binding subsystem are not tracked by spamoor, which leads to reusing them again in different situations. This especially gets worse as you're also using the root wallet directly for this.

I see. Any particular suggestions on how to proceed otherwise?

I kinda get it for the eoa-delegation scenario, as there is a small logical difference compared to the setcodetx scenario by funding the delegators with 1wei each.
(Btw, why is this needed? And is it strictly necessary as a pre-step before doing the delegation?)

This is needed because the cost of setting authorizations to already existing accounts is lower (saving 25kgas/account). We want to write as much code as possible in as many accounts as possible. So I need to be sure all of them are funded prior to set the authorization tuple for them. This is the reason why this scenario works in this way. I think README explains it. But I might need to clarify.

But I don't really get the diff for rand_sstore vs storagespam and erc20-max-transfers vs erctx?
Is it just because you need to generate the summary at the end?

So for rand_sstore and erc20-max-transfers I tried to avoid what happened with eoatx. Which is that I need extra logic because some scenarios are related/depend on eachother. See, when measuring performance, you rarely care about existing state. But when you want to exploit big state, you do. Hence, some of my scenarios bloat contract deployment while others use such contracts to perform bloating inside of them in a combination.
For example:

  • rand_sstore has a "deterministic" storage bloating. Meaning, storing few info I can replicate the whole chain of slots that contain data. This is important because then I can implement scenarios that leaverage this and do Non-0-slot -> Non-zero-slot allowing me to write a lot more data at a cheaper price making the node suffer. Also rand_sload(under construction) reuses the storage slot position acess via deterministic seed to trigger attacks forcing the node to read as many random positions in as many contracts as possible. I can't implement all this logic in your scenario as it will be a lot more complex.
  • erc20-max-transfers is kinda similar. I re-use here the fact that the whole supply of the token is under a single wallet (the root) and I abuse this in order to fund as many new accounts as possible (making the balances mapping grow as much as possible). With that, I can then get reports and know the state size of each contract creating assymetries and bloating some of them way more than others. Allowing me to test more scenarios.

I hope this explains my rationale on why I proceeded this way.

@pk910
Copy link
Member Author

pk910 commented Jun 19, 2025

Heya @CPerezz,

Thanks for clarifying :) The explanations for the scenario helped me understanding the background better.
So, I've included all your statebloat scenario PRs into this PR, and made several adjustments to make the code more streamlined with the rest of the codebase to keep it maintainable.
There were a few issues, like the excessive root wallet usage which should now be fixed too.

Can you have another quick look across the functionality?
I've tried to retain all features, so the scenarios should work the same way.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants