Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 17 additions & 1 deletion actuator/src/main/java/org/tron/core/utils/ProposalUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -871,6 +871,21 @@ public static void validator(DynamicPropertiesStore dynamicPropertiesStore,
}
break;
}
case ALLOW_TVM_OSAKA: {
if (!forkController.pass(ForkBlockVersionEnum.VERSION_4_8_2)) {
throw new ContractValidateException(
"Bad chain parameter id [ALLOW_TVM_OSAKA]");
}
if (dynamicPropertiesStore.getAllowTvmOsaka() == 1) {
throw new ContractValidateException(
"[ALLOW_TVM_OSAKA] has been valid, no need to propose again");
}
if (value != 1) {
throw new ContractValidateException(
"This value[ALLOW_TVM_OSAKA] is only allowed to be 1");
}
break;
}
default:
break;
}
Expand Down Expand Up @@ -955,7 +970,8 @@ public enum ProposalType { // current value, value range
CONSENSUS_LOGIC_OPTIMIZATION(88), // 0, 1
ALLOW_TVM_BLOB(89), // 0, 1
PROPOSAL_EXPIRE_TIME(92), // (0, 31536003000)
ALLOW_TVM_SELFDESTRUCT_RESTRICTION(94); // 0, 1
ALLOW_TVM_SELFDESTRUCT_RESTRICTION(94), // 0, 1
ALLOW_TVM_OSAKA(96); // 0, 1

private long code;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -622,6 +622,8 @@ public static class ModExp extends PrecompiledContract {

private static final int ARGS_OFFSET = 32 * 3; // addresses length part

private static final int UPPER_BOUND = 1024;

@Override
public long getEnergyForData(byte[] data) {

Expand Down Expand Up @@ -660,6 +662,11 @@ public Pair<Boolean, byte[]> execute(byte[] data) {
int expLen = parseLen(data, 1);
int modLen = parseLen(data, 2);

if (VMConfig.allowTvmOsaka()
&& (baseLen > UPPER_BOUND || expLen > UPPER_BOUND || modLen > UPPER_BOUND)) {
return Pair.of(false, EMPTY_BYTE_ARRAY);
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Hey @ouy95917, just a quick curiosity question here — is there a specific calculation or reasoning behind why baseLen, expLen, and modLen are each capped at 1024 bytes specifically? I'm wondering whether this was driven by cryptographic practicality (e.g., covering RSA-8192 as the largest real-world key size), or some other consideration from the EIP authors. Any context you can share — or a pointer to the relevant EIP discussion thread — would be greatly appreciated. Thanks!

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

The 1024-byte (8192-bit) limit was mainly driven by cryptographic practicality — it covers RSA keys up to 8192 bits, which is the largest size used in practice. Ethereum's on-chain analysis (~7 years of mainnet data) confirmed the max observed input was only 513 bytes, so 1024 gives plenty of headroom.

There's a more detailed discussion on this in the TIP issue: tronprotocol/tips#826 — covers the rationale, error semantics, security background, etc. Worth a read if you're interested.


BigInteger base = parseArg(data, ARGS_OFFSET, baseLen);
BigInteger exp = parseArg(data, addSafely(ARGS_OFFSET, baseLen), expLen);
BigInteger mod = parseArg(data, addSafely(addSafely(ARGS_OFFSET, baseLen), expLen), modLen);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ public static void load(StoreFactory storeFactory) {
VMConfig.initDisableJavaLangMath(ds.getConsensusLogicOptimization());
VMConfig.initAllowTvmBlob(ds.getAllowTvmBlob());
VMConfig.initAllowTvmSelfdestructRestriction(ds.getAllowTvmSelfdestructRestriction());
VMConfig.initAllowTvmOsaka(ds.getAllowTvmOsaka());
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,8 @@ public class DynamicPropertiesStore extends TronStoreWithRevoking<BytesCapsule>
private static final byte[] ALLOW_TVM_SELFDESTRUCT_RESTRICTION =
"ALLOW_TVM_SELFDESTRUCT_RESTRICTION".getBytes();

private static final byte[] ALLOW_TVM_OSAKA = "ALLOW_TVM_OSAKA".getBytes();

@Autowired
private DynamicPropertiesStore(@Value("properties") String dbName) {
super(dbName);
Expand Down Expand Up @@ -2980,6 +2982,17 @@ public long getProposalExpireTime() {
.orElse(CommonParameter.getInstance().getProposalExpireTime());
}

public long getAllowTvmOsaka() {
return Optional.ofNullable(getUnchecked(ALLOW_TVM_OSAKA))
.map(BytesCapsule::getData)
.map(ByteArray::toLong)
.orElse(CommonParameter.getInstance().getAllowTvmOsaka());
}

public void saveAllowTvmOsaka(long value) {
this.put(ALLOW_TVM_OSAKA, new BytesCapsule(ByteArray.fromLong(value)));
}

private static class DynamicResourceProperties {

private static final byte[] ONE_DAY_NET_LIMIT = "ONE_DAY_NET_LIMIT".getBytes();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -633,6 +633,10 @@ public class CommonParameter {
@Setter
public long allowTvmBlob;

@Getter
@Setter
public long allowTvmOsaka;

private static double calcMaxTimeRatio() {
return 5.0;
}
Expand Down
5 changes: 3 additions & 2 deletions common/src/main/java/org/tron/core/config/Parameter.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@ public enum ForkBlockVersionEnum {
VERSION_4_7_7(31, 1596780000000L, 80),
VERSION_4_8_0(32, 1596780000000L, 80),
VERSION_4_8_0_1(33, 1596780000000L, 70),
VERSION_4_8_1(34, 1596780000000L, 80);
VERSION_4_8_1(34, 1596780000000L, 80),
VERSION_4_8_2(35, 1596780000000L, 80);
// if add a version, modify BLOCK_VERSION simultaneously

@Getter
Expand Down Expand Up @@ -77,7 +78,7 @@ public class ChainConstant {
public static final int SINGLE_REPEAT = 1;
public static final int BLOCK_FILLED_SLOTS_NUMBER = 128;
public static final int MAX_FROZEN_NUMBER = 1;
public static final int BLOCK_VERSION = 34;
public static final int BLOCK_VERSION = 35;
public static final long FROZEN_PERIOD = 86_400_000L;
public static final long DELEGATE_PERIOD = 3 * 86_400_000L;
public static final long TRX_PRECISION = 1000_000L;
Expand Down
10 changes: 10 additions & 0 deletions common/src/main/java/org/tron/core/vm/config/VMConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ public class VMConfig {

private static boolean ALLOW_TVM_SELFDESTRUCT_RESTRICTION = false;

private static boolean ALLOW_TVM_OSAKA = false;

private VMConfig() {
}

Expand Down Expand Up @@ -172,6 +174,10 @@ public static void initAllowTvmSelfdestructRestriction(long allow) {
ALLOW_TVM_SELFDESTRUCT_RESTRICTION = allow == 1;
}

public static void initAllowTvmOsaka(long allow) {
ALLOW_TVM_OSAKA = allow == 1;
}

public static boolean getEnergyLimitHardFork() {
return CommonParameter.ENERGY_LIMIT_HARD_FORK;
}
Expand Down Expand Up @@ -271,4 +277,8 @@ public static boolean allowTvmBlob() {
public static boolean allowTvmSelfdestructRestriction() {
return ALLOW_TVM_SELFDESTRUCT_RESTRICTION;
}

public static boolean allowTvmOsaka() {
return ALLOW_TVM_OSAKA;
}
}
5 changes: 5 additions & 0 deletions framework/src/main/java/org/tron/core/Wallet.java
Original file line number Diff line number Diff line change
Expand Up @@ -1509,6 +1509,11 @@ public Protocol.ChainParameters getChainParameters() {
.setValue(dbManager.getDynamicPropertiesStore().getProposalExpireTime())
.build());

builder.addChainParameter(Protocol.ChainParameters.ChainParameter.newBuilder()
.setKey("getAllowTvmOsaka")
.setValue(dbManager.getDynamicPropertiesStore().getAllowTvmOsaka())
.build());

return builder.build();
}

Expand Down
4 changes: 4 additions & 0 deletions framework/src/main/java/org/tron/core/config/args/Args.java
Original file line number Diff line number Diff line change
Expand Up @@ -1037,6 +1037,10 @@ public static void applyConfigParams(
config.hasPath(ConfigKey.COMMITTEE_ALLOW_TVM_BLOB) ? config
.getInt(ConfigKey.COMMITTEE_ALLOW_TVM_BLOB) : 0;

PARAMETER.allowTvmOsaka =
config.hasPath(ConfigKey.COMMITTEE_ALLOW_TVM_OSAKA) ? config
.getInt(ConfigKey.COMMITTEE_ALLOW_TVM_OSAKA) : 0;

logConfig();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,7 @@ private ConfigKey() {
public static final String COMMITTEE_ALLOW_TVM_CANCUN = "committee.allowTvmCancun";
public static final String COMMITTEE_ALLOW_TVM_BLOB = "committee.allowTvmBlob";
public static final String COMMITTEE_PROPOSAL_EXPIRE_TIME = "committee.proposalExpireTime";
public static final String COMMITTEE_ALLOW_TVM_OSAKA = "committee.allowTvmOsaka";
public static final String ALLOW_ACCOUNT_ASSET_OPTIMIZATION =
"committee.allowAccountAssetOptimization";
public static final String ALLOW_ASSET_OPTIMIZATION = "committee.allowAssetOptimization";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -392,6 +392,10 @@ public static boolean process(Manager manager, ProposalCapsule proposalCapsule)
manager.getDynamicPropertiesStore().saveProposalExpireTime(entry.getValue());
break;
}
case ALLOW_TVM_OSAKA: {
manager.getDynamicPropertiesStore().saveAllowTvmOsaka(entry.getValue());
break;
}
default:
find = false;
break;
Expand Down
1 change: 1 addition & 0 deletions framework/src/main/resources/config.conf
Original file line number Diff line number Diff line change
Expand Up @@ -759,6 +759,7 @@ committee = {
# allowTvmBlob = 0
# consensusLogicOptimization = 0
# allowOptimizedReturnValueOfChainId = 0
# allowTvmOsaka = 0
}

event.subscribe = {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
package org.tron.common.runtime.vm;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.tuple.Pair;
import org.junit.Assert;
import org.junit.Test;
import org.tron.common.utils.ByteUtil;
import org.tron.core.vm.PrecompiledContracts;
import org.tron.core.vm.config.ConfigLoader;
import org.tron.core.vm.config.VMConfig;

@Slf4j
public class AllowTvmOsakaTest extends VMTestBase {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The current test only covers two cases: all-zero lengths (valid) and an oversized baseLen (invalid). Please add the following cases:

baseLen == 1024 → should succeed (boundary value)
baseLen == 1025 → should fail (just over the limit)
Oversized expLen only → should fail
Oversized modLen only → should fail

All limits exceeded while allowTvmOsaka is disabled → should succeed (no restriction applied)

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Thanks for the review! All suggested test cases have been added in the latest commit:

  • baseLen == 1024 → passes (boundary value)
  • baseLen == 1025 → fails (just over the limit)
  • Oversized expLen only → fails
  • Oversized modLen only → fails
  • All limits exceeded with allowTvmOsaka disabled → passes (no restriction applied)

Also added a helper method toLenBytes(int) for cleaner ABI-encoded length construction. All tests pass locally.


private static final PrecompiledContracts.PrecompiledContract modExp =
new PrecompiledContracts.ModExp();

private static byte[] toLenBytes(int value) {
byte[] b = new byte[32];
b[28] = (byte) ((value >> 24) & 0xFF);
b[29] = (byte) ((value >> 16) & 0xFF);
b[30] = (byte) ((value >> 8) & 0xFF);
b[31] = (byte) (value & 0xFF);
return b;
}

@Test
public void testEIP7823() {
ConfigLoader.disable = true;
VMConfig.initAllowTvmOsaka(1);

try {
// all-zero lengths: should succeed
Pair<Boolean, byte[]> result = modExp.execute(
ByteUtil.merge(toLenBytes(0), toLenBytes(0), toLenBytes(0)));
Assert.assertTrue(result.getLeft());

// baseLen == 1024: boundary, should succeed
result = modExp.execute(
ByteUtil.merge(toLenBytes(1024), toLenBytes(0), toLenBytes(0)));
Assert.assertTrue(result.getLeft());

// baseLen == 1025: just over the limit, should fail
result = modExp.execute(
ByteUtil.merge(toLenBytes(1025), toLenBytes(0), toLenBytes(0)));
Assert.assertFalse(result.getLeft());

// oversized expLen only: should fail
result = modExp.execute(
ByteUtil.merge(toLenBytes(0), toLenBytes(1025), toLenBytes(0)));
Assert.assertFalse(result.getLeft());

// oversized modLen only: should fail
result = modExp.execute(
ByteUtil.merge(toLenBytes(0), toLenBytes(0), toLenBytes(1025)));
Assert.assertFalse(result.getLeft());
} finally {
VMConfig.initAllowTvmOsaka(0);
ConfigLoader.disable = false;
}
}

@Test
public void testEIP7823DisabledShouldPass() {
ConfigLoader.disable = true;
VMConfig.initAllowTvmOsaka(0);

try {
// all limits exceeded while osaka is disabled: should succeed (no restriction)
Pair<Boolean, byte[]> result = modExp.execute(
ByteUtil.merge(toLenBytes(2048), toLenBytes(2048), toLenBytes(2048)));
Assert.assertTrue(result.getLeft());
} finally {
ConfigLoader.disable = false;
}
}
}
Loading