Skip to content

feat(vm): implement TIP-7883 ModExp gas cost increase#6654

Merged
CodeNinjaEvan merged 6 commits into
tronprotocol:developfrom
yanghang8612:implement-tip-7883
May 8, 2026
Merged

feat(vm): implement TIP-7883 ModExp gas cost increase#6654
CodeNinjaEvan merged 6 commits into
tronprotocol:developfrom
yanghang8612:implement-tip-7883

Conversation

@yanghang8612
Copy link
Copy Markdown
Collaborator

@yanghang8612 yanghang8612 commented Apr 8, 2026

Summary

Implements the current TIP-7883 draft (TRON adoption of EIP-7883) by switching the ModExp precompile to the EIP-7883 pricing formula under allowTvmOsaka, and removes the now-redundant config-file plumbing for allowTvmOsaka so activation is proposal-only.

Baseline note: TRON legacy pricing is not EIP-2565

EIP-7883 is specified as a change from EIP-2565, but java-tron's pre-Osaka ModExp pricing still follows the existing EIP-198-style path: the piecewise multiplication complexity with GQUAD_DIVISOR = 20. This PR intentionally implements the TIP/EIP-7883 formula at activation time; it is not a monotonic multiplier over java-tron's current legacy pricing for every possible input.

Examples versus java-tron legacy pricing:

  • nagydani_1_square: 204 -> 500
  • nagydani_2_square: 665 -> 512 (lower than legacy because TIP-7883 follows the newer EIP-2565-family complexity shape)
  • nagydani_5_pow0x10001: 285900 -> 524288

The net energy change is therefore input-dependent. The intended compatibility target is the TIP-7883/EIP-7883 schedule, not preserving a strict increase over every legacy java-tron input.

Pricing formula changes under allowTvmOsaka

  • Minimum energy is raised to 500.
  • Multiplication complexity becomes 16 for maxLen <= 32, and 2 * ceil(maxLen / 8)^2 for maxLen > 32.
  • Iteration count keeps a floor of 1; for expLen > 32, the multiplier changes from the EIP-2565-family 8 to 16.
  • The old pre-Osaka path remains unchanged when allowTvmOsaka == 0.

allowTvmOsaka config-knob removal

The Osaka gate was previously settable from a config file as well as the proposal. This PR makes it proposal-only, mirroring the ALLOW_TVM_SELFDESTRUCT_RESTRICTION shape:

  • CommonParameter.allowTvmOsaka field deleted
  • CommitteeConfig.allowTvmOsaka field deleted
  • Args.applyCommitteeConfig assignment deleted
  • framework/src/main/resources/config.conf sample line deleted
  • common/src/main/resources/reference.conf default deleted
  • DynamicPropertiesStore.getAllowTvmOsaka no longer falls back to CommonParameter; reads the DB and .orElse(0L)

Operators do not lose the governance activation path: Osaka activates strictly through the on-chain proposal.

Gate granularity

allowTvmOsaka intentionally gates Osaka-aligned TVM changes as a coherent upgrade flag rather than one flag per TIP. That keeps TRON's activation model aligned with upstream fork semantics and avoids a partial-Osaka state for cross-chain tooling and gas estimators. If a testnet-only issue is found before activation, the proposal can simply remain off. If a post-activation issue requires separating one behavior, the cleaner follow-up is a subsequent fork-level override flag rather than splitting this activation gate now.

Tests

  • testEIP7883ModExpPricing covers the new floor, the doubled-formula branch at the 33-byte boundary, and standard nagydani vectors.
  • testEIP7883DisabledPreservesOldPricing pins the legacy EIP-198-style pricing when allowTvmOsaka == 0.
  • testEIP7883CanBeLowerThanLegacyPricing documents the non-monotonic comparison against java-tron's current legacy formula.

Spec

Comment on lines +739 to +748
BigInteger energy = BigInteger.valueOf(multComplexity)
.multiply(BigInteger.valueOf(iterCount));

BigInteger minEnergy = BigInteger.valueOf(500);
if (isLessThan(energy, minEnergy)) {
return 500L;
}

return isLessThan(energy, BigInteger.valueOf(Long.MAX_VALUE)) ? energy.longValueExact()
: Long.MAX_VALUE;
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Good defensive coding — using BigInteger for the intermediate multiplication avoids any potential overflow with large baseLen/modLen values (up to 1024 bytes), and the Long.MAX_VALUE cap ensures the result is always safe to return as a long. Well handled.

*/
private long getMultComplexityTIP7883(int baseLen, int modLen) {
long maxLength = max(baseLen, modLen, VMConfig.disableJavaLangMath());
long words = (maxLength + 7) / 8; // ceil(maxLength / 8)
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

The inline comment // ceil(maxLength / 8) is a nice touch — it makes the intent of (maxLength + 7) / 8 immediately clear without needing to mentally decode the arithmetic. The structure also maps 1:1 to the spec's pseudocode, which makes auditing straightforward.

@halibobo1205 halibobo1205 added the topic:vm VM, smart contract label Apr 9, 2026
Copy link
Copy Markdown
Collaborator

@CodeNinjaEvan CodeNinjaEvan left a comment

Choose a reason for hiding this comment

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

LGTM

if (maxLength <= 32) {
return 16;
}
return 2 * words * words;
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[P1] Suggestion: use overflow-safe arithmetic for long-term review burden reduction

2 * words * words uses plain long multiplication. Proving it won't overflow requires tracing the full input chain: parseLen()intValueSafe() returns int → max words = 268,435,456 → 2 * words² = 1.44×10¹⁷ < Long.MAX_VALUE. This reasoning is correct today, but not self-evident — if parseLen() return type or UPPER_BOUND ever changes, the safety assumption silently breaks.

Using overflow-safe arithmetic makes the code self-evidently safe with zero external reasoning required, reducing the review burden for future readers:

return Math.multiplyExact(2, Math.multiplyExact(words, words));

This is a long-term maintainability suggestion, not a current correctness issue.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Thanks for flagging this. Applied in e512e21 — used StrictMathWrapper.multiplyExact instead of Math.multiplyExact to stay consistent with the cross-platform-determinism convention this repo follows (the Maths javadoc explicitly redirects new code to StrictMathWrapper). Same fail-fast guarantee, and reviewers no longer need to trace parseLen() → int → UPPER_BOUND to convince themselves the multiplication is safe.

* Minimal complexity of 16; doubled complexity for base/modulus > 32 bytes.
*/
private long getMultComplexityTIP7883(int baseLen, int modLen) {
long maxLength = max(baseLen, modLen, VMConfig.disableJavaLangMath());
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[SHOULD]getMultComplexityTIP7883 and getIterationCountTIP7883 are new methods with no legacy constraints. They should use StrictMathWrapper directly instead of the deprecated Maths.max(a, b, boolean) pattern.

Suggested changes:

// getMultComplexityTIP7883
- long maxLength = max(baseLen, modLen, VMConfig.disableJavaLangMath());
+ long maxLength = StrictMathWrapper.max(baseLen, modLen);

// avoid silent overflow on 2 * words * words
 - return 2 * words * words;
 + return StrictMathWrapper.multiplyExact(2L, StrictMathWrapper.multiplyExact(words, words));
 
 // getIterationCountTIP7883
 - return max(iterCount, 1, VMConfig.disableJavaLangMath());
 + return StrictMathWrapper.max(iterCount, 1L);

Reasons:

  1. Maths is @Deprecated — new code should not add more callers.
  2. 2 * words * words relies on manual reasoning about value ranges for overflow safety. Using multiplyExact makes this explicit and fail-fast.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Thanks, all three suggestions applied in e512e21getMultComplexityTIP7883 / getIterationCountTIP7883 now call StrictMathWrapper.max directly, and the 2 * words * words product is wrapped in StrictMathWrapper.multiplyExact so the overflow argument no longer depends on parseLen() returning int. Agreed that new code shouldn't keep adding callers to the deprecated Maths helper.

Raise the floor to 500, switch the >32-byte branch to 2*words²,
and bump the long-exponent multiplier to 16. Drop the OSAKA gate's
config-file plumbing — the on-chain proposal is the only switch.
Verify the new floor, the doubled-formula branch at the 33-byte
boundary, and that pre-OSAKA pricing is preserved when the gate
is off.
@yanghang8612 yanghang8612 force-pushed the implement-tip-7883 branch from 287c0b7 to d4bdf30 Compare May 6, 2026 02:27
Make overflow safety explicit instead of relying on int range, and
keep all arithmetic in the new energy helpers consistent with the
existing StrictMathWrapper-based ops.
@yanghang8612 yanghang8612 requested a review from aiden3885 May 8, 2026 07:54
@yanghang8612 yanghang8612 force-pushed the implement-tip-7883 branch from 2bd536e to 7d9201f Compare May 8, 2026 09:42
…-test-fixes

# Conflicts:
#	framework/src/test/java/org/tron/common/runtime/vm/AllowTvmOsakaTest.java
Copy link
Copy Markdown
Collaborator

@CodeNinjaEvan CodeNinjaEvan left a comment

Choose a reason for hiding this comment

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

LGTM

@CodeNinjaEvan CodeNinjaEvan merged commit 02158fc into tronprotocol:develop May 8, 2026
12 checks passed
@github-project-automation github-project-automation Bot moved this to Done in java-tron May 8, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

topic:vm VM, smart contract

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

7 participants