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
Original file line number Diff line number Diff line change
Expand Up @@ -949,7 +949,6 @@ private long increase(long lastUsage, long usage, long lastTime, long now, long
}

if (lastTime != now) {
assert now > lastTime;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2: These asserts were the only guard on two runtime invariants, and removing them turns invalid states into silent miscomputation instead of a loud failure. If now < lastTime (e.g. account state carrying a later latestConsumeTime), the decay factor (windowSize - delta)/windowSize becomes > 1 and inflates energy/net usage; if totalEnergyWeight == 0, the hardened path throws a naked ArithmeticException while the non-hardened path returns Long.MAX_VALUE. Assertions are disabled by default in production, so the checks were only active under -ea (Gradle tests default), but that was the only protection. Replace them with explicit validation that throws regardless of -ea, or document why both invariants are guaranteed by construction, so the removal is justified.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At actuator/src/main/java/org/tron/core/vm/repository/RepositoryImpl.java, line 952:

<comment>These asserts were the only guard on two runtime invariants, and removing them turns invalid states into silent miscomputation instead of a loud failure. If `now < lastTime` (e.g. account state carrying a later latestConsumeTime), the decay factor `(windowSize - delta)/windowSize` becomes > 1 and inflates energy/net usage; if `totalEnergyWeight == 0`, the hardened path throws a naked ArithmeticException while the non-hardened path returns Long.MAX_VALUE. Assertions are disabled by default in production, so the checks were only active under `-ea` (Gradle tests default), but that was the only protection. Replace them with explicit validation that throws regardless of `-ea`, or document why both invariants are guaranteed by construction, so the removal is justified.</comment>

<file context>
@@ -949,7 +949,6 @@ private long increase(long lastUsage, long usage, long lastTime, long now, long
 
     if (lastTime != now) {
-      assert now > lastTime;
       if (lastTime + windowSize > now) {
         long delta = now - lastTime;
         double decay = (windowSize - delta) / (double) windowSize;
</file context>

if (lastTime + windowSize > now) {
long delta = now - lastTime;
double decay = (windowSize - delta) / (double) windowSize;
Expand Down Expand Up @@ -998,8 +997,6 @@ public long calculateGlobalEnergyLimit(AccountCapsule accountCapsule) {
long totalEnergyLimit = getDynamicPropertiesStore().getTotalEnergyCurrentLimit();
long totalEnergyWeight = getDynamicPropertiesStore().getTotalEnergyWeight();

assert totalEnergyWeight > 0;

if (hardenResourceCalculation()) {
return BigInteger.valueOf(energyWeight)
.multiply(BigInteger.valueOf(totalEnergyLimit))
Expand Down
11 changes: 11 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,17 @@ plugins {

ext {
grpcVersion = "1.83.1"
// Netty 4.2 split io.netty.handler.codec.protobuf out of netty-codec into its
// own artifact. Both :framework and :p2p put the varint32 framing codecs on
// their channel pipelines and so must declare it explicitly. Netty itself
// arrives transitively through grpc-netty, so this version has to move with
// grpcVersion above — keeping it here makes that coupling visible instead of
// leaving two literals to drift apart.
nettyVersion = "4.2.15.Final"
// Shared by :protocol and :p2p, which both generate from .proto files.
protobufVersion = "3.25.8"
// Shared by :framework, :plugins and :p2p.
checkstyleVersion = "8.7"
}

allprojects {
Expand Down
Empty file.
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,6 @@ private static long convertVectorToLong(List<Boolean> v) throws ZksnarkException
}

public byte[] encode() throws ZksnarkException {
assert (authenticationPath.size() == index.size());
List<List<Byte>> pathByteList = Lists.newArrayList();
long indexLong; // 64
for (int i = 0; i < authenticationPath.size(); i++) {
Expand Down
Empty file.
3 changes: 0 additions & 3 deletions chainbase/src/main/java/org/tron/core/db/EnergyProcessor.java
Original file line number Diff line number Diff line change
Expand Up @@ -155,8 +155,6 @@ public long calculateGlobalEnergyLimit(AccountCapsule accountCapsule) {
long totalEnergyWeight = dynamicPropertiesStore.getTotalEnergyWeight();
if (dynamicPropertiesStore.allowNewReward() && totalEnergyWeight <= 0) {
return 0;
} else {
assert totalEnergyWeight > 0;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2: Removing this else-assert is safe only in the sense that assertions were never enabled here — but it was the sole tripwire for a real gap this method still has. When allowNewReward() returns false and totalEnergyWeight == 0 (weight is stored raw, not clamped while allowNewReward is off), execution falls through to (double) totalEnergyLimit / totalEnergyWeight, yielding Long.MAX_VALUE in the non-hardened path or an ArithmeticException in calculateGlobalLimitV1. Both calculateGlobalEnergyLimitV2 (returns 0 when weight == 0) and BandwidthProcessor's totalNetWeight == 0 guard handle the same case unconditionally. Replace the assert with an unconditional totalEnergyWeight <= 0 guard.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At chainbase/src/main/java/org/tron/core/db/EnergyProcessor.java, line 159:

<comment>Removing this else-assert is safe only in the sense that assertions were never enabled here — but it was the sole tripwire for a real gap this method still has. When `allowNewReward()` returns false and `totalEnergyWeight == 0` (weight is stored raw, not clamped while allowNewReward is off), execution falls through to `(double) totalEnergyLimit / totalEnergyWeight`, yielding `Long.MAX_VALUE` in the non-hardened path or an `ArithmeticException` in `calculateGlobalLimitV1`. Both `calculateGlobalEnergyLimitV2` (returns 0 when weight == 0) and BandwidthProcessor's `totalNetWeight == 0` guard handle the same case unconditionally. Replace the assert with an unconditional `totalEnergyWeight <= 0` guard.</comment>

<file context>
@@ -155,8 +155,6 @@ public long calculateGlobalEnergyLimit(AccountCapsule accountCapsule) {
-    } else {
-      assert totalEnergyWeight > 0;
     }
     if (hardenCalculation()) {
       return calculateGlobalLimitV1(frozeBalance, totalEnergyLimit, totalEnergyWeight);
@@ -205,4 +203,3 @@ private long scaleByRate(long value, long numerator, long denominator) {
</file context>

}
if (hardenCalculation()) {
return calculateGlobalLimitV1(frozeBalance, totalEnergyLimit, totalEnergyWeight);
Expand Down Expand Up @@ -205,4 +203,3 @@ private long scaleByRate(long value, long numerator, long denominator) {
}
}


Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,6 @@ protected long increase(long lastUsage, long usage, long lastTime, long now, lon
}

if (lastTime != now) {
assert now > lastTime;
if (lastTime + windowSize > now) {
long delta = now - lastTime;
double decay = (windowSize - delta) / (double) windowSize;
Expand Down
18 changes: 1 addition & 17 deletions common/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -23,23 +23,7 @@ dependencies {
api 'org.aspectj:aspectjrt:1.9.8'
api 'org.aspectj:aspectjweaver:1.9.8'
api 'org.aspectj:aspectjtools:1.9.8'
api group: 'io.github.tronprotocol', name: 'libp2p', version: '2.2.9',{
exclude group: 'io.grpc', module: 'grpc-context'
exclude group: 'io.grpc', module: 'grpc-core'
exclude group: 'io.grpc', module: 'grpc-netty'
exclude group: 'com.google.protobuf', module: 'protobuf-java'
exclude group: 'com.google.protobuf', module: 'protobuf-java-util'
// https://github.com/dom4j/dom4j/pull/116
// https://github.com/gradle/gradle/issues/13656
// https://github.com/dom4j/dom4j/issues/99
exclude group: 'jaxen', module: 'jaxen'
exclude group: 'javax.xml.stream', module: 'stax-api'
exclude group: 'net.java.dev.msv', module: 'xsdlib'
exclude group: 'pull-parser', module: 'pull-parser'
exclude group: 'xpp3', module: 'xpp3'
exclude group: 'org.bouncycastle', module: 'bcprov-jdk18on'
exclude group: 'org.bouncycastle', module: 'bcutil-jdk18on'
}
api project(":p2p")
api project(":protocol")
api project(":platform")
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
package org.tron.core.config.args;

import static org.tron.core.exception.TronError.ErrCode.PARAMETER_INIT;

import com.typesafe.config.Config;
import com.typesafe.config.ConfigBeanFactory;
import com.typesafe.config.ConfigValue;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.tron.core.exception.TronError;

/**
* Committee (governance) configuration bean.
Expand Down Expand Up @@ -160,11 +163,11 @@ private void postProcess() {
// cross-field: allowOldRewardOpt requires at least one reward/vote flag
if (allowOldRewardOpt == 1 && allowNewRewardAlgorithm != 1
&& allowNewReward != 1 && allowTvmVote != 1) {
throw new IllegalArgumentException(
throw new TronError(
"At least one of the following proposals is required to be opened first: "
+ "committee.allowNewRewardAlgorithm = 1"
+ " or committee.allowNewReward = 1"
+ " or committee.allowTvmVote = 1.");
+ " or committee.allowTvmVote = 1.", PARAMETER_INIT);
}
}
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
package org.tron.core.config.args;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThrows;

import com.typesafe.config.Config;
import com.typesafe.config.ConfigFactory;
import org.junit.Test;
import org.tron.core.exception.TronError;

public class CommitteeConfigTest {

Expand Down Expand Up @@ -57,9 +59,16 @@ public void testDynamicEnergyThresholdClamped() {
.getDynamicEnergyThreshold());
}

@Test(expected = IllegalArgumentException.class)
@Test
public void testAllowOldRewardOptWithoutPrerequisites() {
CommitteeConfig.fromConfig(withRef("committee { allowOldRewardOpt = 1 }"));
TronError error = assertThrows(TronError.class,
() -> CommitteeConfig.fromConfig(withRef("committee { allowOldRewardOpt = 1 }")));

assertEquals(TronError.ErrCode.PARAMETER_INIT, error.getErrCode());
assertEquals("At least one of the following proposals is required to be opened first: "
+ "committee.allowNewRewardAlgorithm = 1"
+ " or committee.allowNewReward = 1"
+ " or committee.allowTvmVote = 1.", error.getMessage());
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,22 +76,6 @@ public static class Blake2bfDigest implements Digest {
v = new long[16];
}

// for tests
Blake2bfDigest(
final long[] h, final long[] m, final long[] t, final boolean f, final long rounds) {
assert rounds <= 4294967295L; // uint max value
buffer = new byte[MESSAGE_LENGTH_BYTES];
bufferPos = 0;

this.h = h;
this.m = m;
this.t = t;
this.f = f;
this.rounds = rounds;

v = new long[16];
}

@Override
public String getAlgorithmName() {
return "BLAKE2f";
Expand Down
27 changes: 21 additions & 6 deletions framework/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,7 @@ apply plugin: 'checkstyle'

mainClassName = 'org.tron.program.FullNode'

def versions = [
checkstyle: '8.7',
]




Expand All @@ -40,7 +38,7 @@ dependencies {
// end local libraries
implementation group: 'com.beust', name: 'jcommander', version: '1.78'
implementation group: 'io.dropwizard.metrics', name: 'metrics-core', version: '3.1.2'
implementation('io.netty:netty-codec-protobuf:4.2.15.Final') {
implementation("io.netty:netty-codec-protobuf:${rootProject.nettyVersion}") {
exclude group: 'com.google.protobuf'
exclude group: 'com.google.protobuf.nano'
}
Expand All @@ -61,17 +59,28 @@ dependencies {

testImplementation group: 'org.springframework', name: 'spring-test', version: "${springVersion}"
testImplementation group: 'javax.portlet', name: 'portlet-api', version: '3.0.1'

implementation group: 'org.zeromq', name: 'jeromq', version: '0.5.3'
api project(":chainbase")
api project(":protocol")
api project(":actuator")
api project(":consensus")
// org.tron.p2p is used directly in 17 files under src/main/java (org.tron.core.net
// and org.tron.core.config.args). It currently arrives only transitively, three
// hops away, because :common exposes it via `api project(":p2p")` -- and :common
// has to, since CommonParameter publishes P2pConfig/PublishConfig in its own API.
// Declare the direct use here as well, so framework keeps compiling if that
// transitive chain is ever narrowed. api, not implementation: framework does
// re-export p2p types -- P2pEventHandlerImpl extends org.tron.p2p.P2pEventHandler,
// HelloMessage.getFrom() returns org.tron.p2p.discover.Node, PeerManager takes
// org.tron.p2p.connection.Channel, Args.loadDnsPublishConfig returns PublishConfig.
api project(":p2p")
}

check.dependsOn 'lint'

checkstyle {
toolVersion = "${versions.checkstyle}"
toolVersion = "${rootProject.checkstyleVersion}"
configFile = file("config/checkstyle/checkStyleAll.xml")
maxWarnings = 0
}
Expand Down Expand Up @@ -187,8 +196,14 @@ def binaryRelease(taskName, jarName, mainClass) {
}

// explicit_dependency
// :p2p is included because :common now exposes it via `api project(":p2p")`,
// so p2p-1.0.0.jar is on runtimeClasspath and gets zipped into the fat jar.
// Without it Gradle reports an implicit_dependency and disables execution
// optimizations, and a parallel build could assemble FullNode.jar before
// :p2p:jar has been written.
dependsOn (project(':actuator').jar, project(':consensus').jar, project(':chainbase').jar,
project(':crypto').jar, project(':common').jar, project(':protocol').jar, project(':platform').jar)
project(':crypto').jar, project(':common').jar, project(':protocol').jar,
project(':platform').jar, project(':p2p').jar)

from {
configurations.runtimeClasspath.collect {
Expand Down
9 changes: 5 additions & 4 deletions framework/src/main/java/org/tron/core/config/args/Args.java
Original file line number Diff line number Diff line change
Expand Up @@ -1045,8 +1045,9 @@ private static void loadDnsPublishParameters(NodeConfig.DnsConfig dns,
String serverType = dns.getServerType();
if (StringUtils.isNotEmpty(serverType)) {
if (!"aws".equalsIgnoreCase(serverType) && !"aliyun".equalsIgnoreCase(serverType)) {
throw new IllegalArgumentException(
"Check node.dns.serverType, must be aws or aliyun");
throw new TronError(
"Check node.dns.serverType, must be aws or aliyun",
TronError.ErrCode.PARAMETER_INIT);
}
if ("aws".equalsIgnoreCase(serverType)) {
publishConfig.setDnsType(DnsType.AwsRoute53);
Expand Down Expand Up @@ -1088,7 +1089,8 @@ private static void loadDnsPublishParameters(NodeConfig.DnsConfig dns,
}

private static void logEmptyError(String arg) {
throw new IllegalArgumentException(String.format("Check %s, must not be null or empty", arg));
throw new TronError(String.format("Check %s, must not be null or empty", arg),

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P3: This changes the exception contract of the public loadDnsPublishParameters path from IllegalArgumentException (RuntimeException) to TronError, which extends Error. Any caller or test that catches Exception/RuntimeException/IllegalArgumentException around config parsing will no longer intercept these failures — Error bypasses those handlers. If the goal is just to carry an exit code (PARAMETER_INIT=1), make TronError extend RuntimeException, or confirm and document this deliberate contract change, since the PR description states 'no functional changes'.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At framework/src/main/java/org/tron/core/config/args/Args.java, line 1092:

<comment>This changes the exception contract of the public loadDnsPublishParameters path from IllegalArgumentException (RuntimeException) to TronError, which extends Error. Any caller or test that catches Exception/RuntimeException/IllegalArgumentException around config parsing will no longer intercept these failures — Error bypasses those handlers. If the goal is just to carry an exit code (PARAMETER_INIT=1), make TronError extend RuntimeException, or confirm and document this deliberate contract change, since the PR description states 'no functional changes'.</comment>

<file context>
@@ -1088,7 +1089,8 @@ private static void loadDnsPublishParameters(NodeConfig.DnsConfig dns,
 
   private static void logEmptyError(String arg) {
-    throw new IllegalArgumentException(String.format("Check %s, must not be null or empty", arg));
+    throw new TronError(String.format("Check %s, must not be null or empty", arg),
+        TronError.ErrCode.PARAMETER_INIT);
   }
</file context>

TronError.ErrCode.PARAMETER_INIT);
}

// createTriggerConfig removed — logic moved to applyEventConfig()
Expand Down Expand Up @@ -1315,4 +1317,3 @@ private static Map<String, String[]> getOptionGroup() {
return optionGroupMap;
}
}

58 changes: 58 additions & 0 deletions framework/src/test/java/org/tron/core/config/args/ArgsTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -519,6 +519,64 @@ public void testMaxMessageSizeNegativeValueRejected() {
}
}

@Test
public void testDnsPublishRejectsInvalidServerTypeWithParameterInitError() {
Config config = dnsPublishConfig(
"node.dns.serverType", "unsupported");

TronError error = Assert.assertThrows(TronError.class,
() -> Args.loadDnsPublishConfig(NodeConfig.fromConfig(config)));

Assert.assertEquals(TronError.ErrCode.PARAMETER_INIT, error.getErrCode());
Assert.assertEquals("Check node.dns.serverType, must be aws or aliyun",
error.getMessage());
}

@Test
public void testDnsPublishRejectsEmptyRequiredParameterWithParameterInitError() {
Config config = dnsPublishConfig("node.dns.dnsDomain", "");

TronError error = Assert.assertThrows(TronError.class,
() -> Args.loadDnsPublishConfig(NodeConfig.fromConfig(config)));

Assert.assertEquals(TronError.ErrCode.PARAMETER_INIT, error.getErrCode());
Assert.assertEquals("Check node.dns.dnsDomain, must not be null or empty",
error.getMessage());
}

@Test
public void testCommitteeConfigRejectsOldRewardOptimizationWithoutPrerequisite() {
Map<String, Object> configMap = new HashMap<>();
configMap.put("storage.db.directory", "database");
configMap.put("committee.allowOldRewardOpt", 1);
Config config = ConfigFactory.parseMap(configMap)
.withFallback(ConfigFactory.defaultReference());

try {
TronError error = Assert.assertThrows(TronError.class,
() -> Args.applyConfigParams(config));

Assert.assertEquals(TronError.ErrCode.PARAMETER_INIT, error.getErrCode());
} finally {
Args.clearParam();
}
}

private Config dnsPublishConfig(String key, String value) {
Map<String, Object> configMap = new HashMap<>();
configMap.put("node.dns.publish", true);
configMap.put("node.dns.dnsDomain", "nodes.example.org");
configMap.put("node.dns.dnsPrivate",
"1234567890123456789012345678901234567890123456789012345678901234");
configMap.put("node.dns.serverType", "aliyun");
configMap.put("node.dns.accessKeyId", "access-key-id");
configMap.put("node.dns.accessKeySecret", "access-key-secret");
configMap.put("node.dns.aliyunDnsEndpoint", "dns.aliyuncs.com");
configMap.put(key, value);
return ConfigFactory.parseMap(configMap)
.withFallback(ConfigFactory.defaultReference());
}

@Test
public void testRpcMaxMessageSizeExceedsIntMax() {
// HOCON's Config.getInt() throws when a numeric value exceeds int range.
Expand Down
21 changes: 21 additions & 0 deletions gradle/verification-metadata.xml
Original file line number Diff line number Diff line change
Expand Up @@ -448,6 +448,14 @@
<sha256 value="afded6e6a690fbf3ad4ae65ada397f0a90a5f630b303d1b741b9c97926fdd4de" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="com.google.code.gson" name="gson" version="2.9.0">
<artifact name="gson-2.9.0.jar">
<sha256 value="c96d60551331a196dac54b745aa642cd078ef89b6f267146b705f2c2cbef052d" origin="Generated by Gradle"/>
</artifact>
<artifact name="gson-2.9.0.pom">
<sha256 value="7190d0b07f278e9f4c603f44e543940f81cf1a2559f851c6f298c9bb2be2978c" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="com.google.code.gson" name="gson-parent" version="2.13.2">
<artifact name="gson-parent-2.13.2.pom">
<sha256 value="83ab528a9d50fd76aeb8ad6f727b3ee9cb766586255774ed16ca8c4c76d9dacd" origin="Generated by Gradle"/>
Expand All @@ -463,6 +471,11 @@
<sha256 value="b16e026e63427c1972ad0fc68703ec379b1576e411ba49c32fa9a31ab0bbcffb" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="com.google.code.gson" name="gson-parent" version="2.9.0">
<artifact name="gson-parent-2.9.0.pom">
<sha256 value="af781c9a5766ffea311a0df0536576a64decc661aa110c4de5c73ac8bf434424" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="com.google.errorprone" name="error_prone_annotation" version="2.42.0">
<artifact name="error_prone_annotation-2.42.0.jar">
<sha256 value="e8ef6e0314bd0ab5595e4274b7cf78964c525685827ae5f4f3d0feffb4da5f11" origin="Generated by Gradle"/>
Expand Down Expand Up @@ -1981,6 +1994,14 @@
<sha256 value="ce7abb4a91ba5d2a73fdf17a3df4762e3605a0392cc7983ef2f1ae16cd384cc3" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="org.bouncycastle" name="bcutil-jdk18on" version="1.84">
<artifact name="bcutil-jdk18on-1.84.jar">
<sha256 value="b374e16963421fb9cfb01cc20d7ad8fd2f8b8188e3eef0ec0a8965e245f7619a" origin="Generated by Gradle"/>
</artifact>
<artifact name="bcutil-jdk18on-1.84.pom">
<sha256 value="0b0cb81a65ee1737d51286350a9e56489336b8f9908198febd0494243eea2978" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="org.checkerframework" name="checker-compat-qual" version="2.0.0">
<artifact name="checker-compat-qual-2.0.0.jar">
<sha256 value="a40b2ce6d8551e5b90b1bf637064303f32944d61b52ab2014e38699df573941b" origin="Generated by Gradle"/>
Expand Down
2 changes: 2 additions & 0 deletions p2p/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# protobuf generated code (rebuilt by ./gradlew :p2p:generateProto)
src/main/java/org/tron/p2p/protos/
Loading
Loading