Skip to content

Conversation

siladu
Copy link
Contributor

@siladu siladu commented May 15, 2025

PR description

We introduce an upper bound to the inputs of the precompile, each of the length inputs (length_of_BASE, length_of_EXPONENT and length_of_MODULUS) MUST be less than or equal to 8192 bits (1024 bytes).

If any of these inputs are larger than the limit, the precompile execution stops, returns an error, and consumes all gas.

TODO

  • Osaka fork activation
  • units
  • Separate issue: update EEST version Update EEST to v4.5.0 #8641
  • Confirm no (performance?) issue introducing explicit upperBound test to Byzantium (Long.MAX_VALUE)
  • Regression test (mainnet sync versus control)
  • Performance test / benchmarks

Fixed Issue(s)

Fixes #8602

Thanks for sending a pull request! Have you done the following?

  • Checked out our contribution guidelines?
  • Considered documentation and added the doc-change-required label to this PR if updates are required.
  • Considered the changelog and included an update if required.
  • For database changes (e.g. KeyValueSegmentIdentifier) considered compatibility and performed forwards and backwards compatibility tests

Locally, you can run these tests to catch failures early:

  • spotless: ./gradlew spotlessApply
  • unit tests: ./gradlew build
  • acceptance tests: ./gradlew acceptanceTest
  • integration tests: ./gradlew integrationTest
  • reference tests: ./gradlew ethereum:referenceTests:referenceTests

Signed-off-by: Simon Dudley <simon.dudley@consensys.net>
@siladu siladu added this to Osaka May 15, 2025
@siladu siladu moved this to In Progress in Osaka May 15, 2025
siladu added 2 commits May 19, 2025 14:37
Signed-off-by: Simon Dudley <simon.dudley@consensys.net>
Signed-off-by: Simon Dudley <simon.dudley@consensys.net>
@siladu siladu changed the title EIP-7823 - Modexp upper bounds [DO NOT MERGE] EIP-7823 - Modexp upper bounds May 19, 2025
Signed-off-by: Simon Dudley <simon.dudley@consensys.net>
*/
public static BigIntegerModularExponentiationPrecompiledContract osaka(
final GasCalculator gasCalculator) {
return new BigIntegerModularExponentiationPrecompiledContract(gasCalculator, OSAKA_UPPER_BOUND);
Copy link
Member

@lu-pinto lu-pinto May 21, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks like an usual design, not consistent with our code - IMO this static logic does not belong here but can be accessed through MainnetPrecompiledContracts::byzantium and MainnetPrecompiledContracts::osaka. The duty to configure these things should be on the caller (configuration) not the instance itself.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let me know what you think 9b34bf9

Copy link
Contributor Author

@siladu siladu May 25, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you mean static factory pattern is an unusual design or something specific to this?

The usage of static factory follows the design already in place for some precompiles e.g AltBN128AddPrecompiledContract.byzantium

I think it's pretty conventional for the static factory to live with the class it's constructing and be responsible for configuring the "osaka" version of it.

If you look through MainnetProtocolSpecs, a lot of fork configuration is done by wiring in a fork-specific version of a class, which extends the previous one, e.g. GasCalculator.

The difference here is we wire in a static factory instead of a whole new version of the class, since it's only one value that is changed.

However, if there is a performance issue with the extra check for prague though, wiring in e.g. OsakaBigIntegerModularExponentiationPrecompiledContract is more code but might be easier to JIT compile (we can check profiling to confirm).

Let me know what you think 9b34bf9

No objections in general, but I think my approach is more conventional, at least in Besu.
No configuration currently exists in MainnetPrecompiledContracts, it's just wiring. That's mostly the case for MainnetProtocolSpecs too, with some exceptions. Most config happens in the fork-specific classes I believe.

Copy link
Member

@lu-pinto lu-pinto May 26, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you mean static factory pattern is an unusual design or something specific to this?

Not that it's unusual but it looks a bit weird like this IMO. So you have 2 places you have to modify if you want to add a new fork even if such fork only lowers the limits, MainnetPrecompiledContracts and BigIntegerModularExponentiationPrecompiledContract with a corresponding static method.

The usage of static factory follows the design already in place for some precompiles e.g AltBN128AddPrecompiledContract.byzantium

Right... I missed this case. I only looked at populateForPrague and they are all using constructors. I think the one of the problems is not being consistent, as there are 2 different approaches in parallel.

If you look through MainnetProtocolSpecs, a lot of fork configuration is done by wiring in a fork-specific version of a class, which extends the previous one, e.g. GasCalculator.

Not sure I understand the example - that actually seems to prove my point. So you have all of the different parts constructed in MainnetProtocolSpecs and MainnetEVMs not in ProtocolSpec neither in EVM - these simply provide the constructor, not the specific static constructor for the fork, and MainnetProtocolSpecs and MainnetEVMs instantiate with the right parameters. If we had static factories for every fork in every class it would be a lot of boiler plate.

However, if there is a performance issue with the extra check for prague though, wiring in e.g. OsakaBigIntegerModularExponentiationPrecompiledContract is more code but might be easier to JIT compile (we can check profiling to confirm).

Yes, I think you are referring to the size of the method. It impacts JIT compilation for sure. Though these are configutation methods - they are not hot - so performance is not really a concern here.

I also think that the statics here degrade the testability of BigIntegerModularExponentiationPrecompiledContract because now there's no way to inject dependencies into the class for testing since all constructors are private. The first temptation would be to package-private the constructor for testing which makes it even worse.

On a separate segway, not sure why MainnetPrecompiledContracts is an interface since it's clearly a factory class 😆

|| length_of_EXPONENT > upperBound
|| length_of_MODULUS > upperBound) {
return PrecompileContractResult.halt(
null, Optional.of(ExceptionalHaltReason.PRECOMPILE_ERROR));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Need to have a unit test for this

Copy link
Contributor Author

@siladu siladu May 25, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yep, this was first draft for the devnet, planning to productionise next. Good reminder 👍

final Bytes input,
final long length_of_BASE,
final long length_of_EXPONENT,
final long length_of_MODULUS) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: why using underscores in variable names

Copy link
Contributor Author

@siladu siladu May 25, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is to match the spec - controversial in java conventions perhaps, but I find it's really useful if the spec and code values match for future reference.

final int modulusLength = clampedToInt(modulusLength(input));
private PrecompileContractResult computeNative(
final @Nonnull Bytes input, final long length_of_MODULUS) {
final int modulusLength = clampedToInt(length_of_MODULUS);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@macfarla macfarla added the Osaka Osaka fork related - part of Fusaka label May 23, 2025
Signed-off-by: Simon Dudley <simon.dudley@consensys.net>
@siladu siladu force-pushed the eip7823-modexp-upper-bounds branch from 8bf2d0c to 5b6f3b8 Compare May 29, 2025 06:39
Signed-off-by: Simon Dudley <simon.dudley@consensys.net>
@siladu
Copy link
Contributor Author

siladu commented May 29, 2025

Using Benchmark.java, I see no significant difference between main and this branch. The most significant are highlight in bold but it goes in both directions so maybe just noise...
Screenshot 2025-05-29 at 6 57 51 pm

Signed-off-by: Simon Dudley <simon.dudley@consensys.net>
@lu-pinto
Copy link
Member

lu-pinto commented Jun 4, 2025

In order to avoid running this off my laptop as it is not great for benchmarking due to other things running, I used a cloud instance. Results for Prague:
image

And results for Osaka:
image

There is some variance in one or 2 test cases but I think it's just noise, test case is too trivial.

@siladu siladu marked this pull request as ready for review June 4, 2025 09:49
@siladu
Copy link
Contributor Author

siladu commented Jun 4, 2025

Confirm no (performance?) issue introducing explicit upperBound test to Byzantium (Long.MAX_VALUE)

It might just be noise at these levels, but I measure a small impact with profiling, 2% performance impact in the worst case. I think it's negligible and we will be on Fusaka soon enough anyway.

modexp-benchmark-subcommand-profiling.tar.gz

@siladu
Copy link
Contributor Author

siladu commented Jun 4, 2025

Regression test (mainnet sync versus control)

No performance difference spotted on mainnet, profiling for 10 minutes didn't show modexp at all, so must be rarely used.

@siladu siladu changed the title [DO NOT MERGE] EIP-7823 - Modexp upper bounds EIP-7823 - Modexp upper bounds Jun 4, 2025
siladu added 2 commits June 4, 2025 20:06
Signed-off-by: Simon Dudley <simon.dudley@consensys.net>
Signed-off-by: Simon Dudley <simon.dudley@consensys.net>
@siladu siladu merged commit 1a206fc into hyperledger:main Jun 4, 2025
52 of 67 checks passed
@github-project-automation github-project-automation bot moved this from In Progress to Done in Osaka Jun 4, 2025
@siladu siladu deleted the eip7823-modexp-upper-bounds branch June 4, 2025 11:06
Gabriel-Trintinalia added a commit that referenced this pull request Jun 6, 2025
* EIP-7825: Transaction gas limit cap (#8700)

* EIP-7825: Transaction gas limit cap

Signed-off-by: Fabio Di Fabio <fabio.difabio@consensys.net>

* Support transaction gas limit cap when simulating a tx

Signed-off-by: Fabio Di Fabio <fabio.difabio@consensys.net>

* Do not allow isAllowExceedingGasLimit for when block simulation is strict

Signed-off-by: Gabriel-Trintinalia <gabriel.trintinalia@consensys.net>

---------

Signed-off-by: Fabio Di Fabio <fabio.difabio@consensys.net>
Signed-off-by: Gabriel-Trintinalia <gabriel.trintinalia@consensys.net>
Co-authored-by: Gabriel-Trintinalia <gabriel.trintinalia@consensys.net>

* EIP-7823 - Modexp upper bounds (#8632)

Signed-off-by: Simon Dudley <simon.dudley@consensys.net>

* Change Maven artifactIds to avoid possible collisions with other libs (#8589)

* Improve Maven artifacts naming to avoid possible collisions with other libs

Signed-off-by: Fabio Di Fabio <fabio.difabio@consensys.net>

* Rename besu subproject to app (#8746)

* Rename `besu` module to `app`

Signed-off-by: Fabio Di Fabio <fabio.difabio@consensys.net>

* Implement percentiles array size limit for eth_feeHistory (#8748)

* implement percentiles array size limit for eth_feeHistory

Signed-off-by: garyschulte <garyschulte@gmail.com>

* Revert "feat: remove chain head check if peer supports eth/69 (#8725)" (#8753)

This reverts commit ed1086d.

Signed-off-by: Gabriel-Trintinalia <gabriel.trintinalia@consensys.net>

---------

Signed-off-by: Fabio Di Fabio <fabio.difabio@consensys.net>
Signed-off-by: Gabriel-Trintinalia <gabriel.trintinalia@consensys.net>
Signed-off-by: Simon Dudley <simon.dudley@consensys.net>
Signed-off-by: garyschulte <garyschulte@gmail.com>
Co-authored-by: Fabio Di Fabio <fabio.difabio@consensys.net>
Co-authored-by: Simon Dudley <simon.dudley@consensys.net>
Co-authored-by: garyschulte <garyschulte@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Osaka Osaka fork related - part of Fusaka
Projects
Status: Done
Development

Successfully merging this pull request may close these issues.

EIP-7823 MODEXP upper bounds
3 participants