Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
15a1d7b
test(framework): fix test quality issues in framework unit tests
Little-Peony Apr 6, 2026
6964695
test(plugins): fix test quality issues in plugins unit tests
Little-Peony Apr 6, 2026
ec640a6
test(actuator): remove obsolete moreThanFrozenNumber test in FreezeBa…
Little-Peony Apr 6, 2026
4316815
test(framework): fix test cleanup and solidity node shutdown
Little-Peony Apr 7, 2026
c4aac32
test(framework): replace bare Executors with ExecutorServiceManager a…
Little-Peony Apr 23, 2026
0ac9b64
test(framework): unify app context fixtures in service tests
Little-Peony Apr 7, 2026
890e9b8
style(test): fix import order to satisfy checkstyle
Little-Peony Apr 8, 2026
1f063c3
chore(config): remove /.dev/ from .gitignore
Little-Peony Apr 8, 2026
54e3802
style(test): fix import order in SolidityNodeTest
Little-Peony Apr 8, 2026
0c22d0f
test(framework): use assertSame for exception identity check in Solid…
Little-Peony Apr 8, 2026
56f17fe
fix(net): guard relay nodes in peer connection
Little-Peony Apr 8, 2026
0e6bbbf
test(framework,plugins): fix flaky tests in bandwidth, stats and db-move
Little-Peony Apr 8, 2026
49e656a
refactor(framework): promote relayNodes to instance field in PeerConn…
Little-Peony Apr 8, 2026
4506ec9
refactor(tvm): optimize energy cost calculation for vote witness opcode
yanghang8612 Mar 31, 2026
d12d6df
fix(framework): replace while(true) with while(flag) in SolidityNode
Little-Peony Apr 13, 2026
962bef3
fix(framework): add null/0 return after while(flag) loops in Solidity…
Little-Peony Apr 13, 2026
c91b8b1
fix(test): add comments
Little-Peony Apr 13, 2026
b6700a0
test(framework): address PR review comments on test code quality
Little-Peony Apr 14, 2026
6731f1b
fix: use Assert.assertThrows to replace try/catch
Little-Peony Apr 14, 2026
b6ec6e1
fix: pr review
Little-Peony Apr 14, 2026
dbc6aba
test(framework): replace Assert.fail with throws Exception in test me…
Little-Peony Apr 16, 2026
233e1b6
test(framework): address PR review nits in BlockEventGetTest and Peer…
Little-Peony Apr 22, 2026
b33b03c
refactor(framework): address shutdown correctness issues from PR review
Little-Peony Apr 23, 2026
20b3a06
refactor(framework): address PR review nits from bladehan1
Little-Peony Apr 23, 2026
214363f
refactor(net): revert relayNodes to local variable in setChannel
Little-Peony Apr 23, 2026
a63d603
style(net): add empty line before setChannel method in PeerConnection
Little-Peony Apr 24, 2026
b7f4c32
fix(backup): restore restart loop, fix channel visibility race only
Little-Peony Apr 24, 2026
35bc7b1
fix(test): remove stale relayNodes field injection in PeerManagerTest
Little-Peony Apr 24, 2026
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 @@ -27,7 +27,7 @@ public class BackupServer implements AutoCloseable {

private BackupManager backupManager;

private Channel channel;
private volatile Channel channel;

private volatile boolean shutdown = false;

Expand Down Expand Up @@ -77,6 +77,12 @@ public void initChannel(NioDatagramChannel ch)

logger.info("Backup server started, bind port {}", port);

// If close() was called while bind() was in progress, channel was not yet visible;
// check again before blocking on closeFuture to avoid hanging indefinitely.
if (shutdown) {
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] This scenario won't exist in the runtime environment. If it's just for fixing unit tests, there's no need to change this logic; simply preventing the backup service from starting would suffice.

channel.close();
break;
}
channel.closeFuture().sync();
if (shutdown) {
logger.info("Shutdown backup BackupServer");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,6 @@
@Scope("prototype")
public class PeerConnection {

private static List<InetSocketAddress> relayNodes = Args.getInstance().getFastForwardNodes();

@Getter
private PeerStatistics peerStatistics = new PeerStatistics();

Expand Down Expand Up @@ -166,7 +164,9 @@ public class PeerConnection {

public void setChannel(Channel channel) {
this.channel = channel;
if (relayNodes.stream().anyMatch(n -> n.getAddress().equals(channel.getInetAddress()))) {
List<InetSocketAddress> relayNodes = Args.getInstance().getFastForwardNodes();
if (relayNodes != null
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.

Under what circumstances would relayNodes == null hold? Is there a unit test for this?

&& relayNodes.stream().anyMatch(n -> n.getAddress().equals(channel.getInetAddress()))) {
this.isRelayPeer = true;
}
this.nodeStatistics = TronStatsManager.getNodeStatistics(channel.getInetAddress());
Expand Down
43 changes: 37 additions & 6 deletions framework/src/main/java/org/tron/program/SolidityNode.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@

import static org.tron.core.config.Parameter.ChainConstant.BLOCK_PRODUCED_INTERVAL;

import com.google.common.annotations.VisibleForTesting;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
Expand All @@ -11,6 +14,7 @@
import org.tron.common.application.ApplicationFactory;
import org.tron.common.application.TronApplicationContext;
import org.tron.common.client.DatabaseGrpcClient;
import org.tron.common.es.ExecutorServiceManager;
import org.tron.common.parameter.CommonParameter;
import org.tron.common.prometheus.Metrics;
import org.tron.core.ChainBaseManager;
Expand Down Expand Up @@ -39,6 +43,9 @@ public class SolidityNode {

private volatile boolean flag = true;

private ExecutorService getBlockEs;
private ExecutorService processBlockEs;

public SolidityNode(Manager dbManager) {
this.dbManager = dbManager;
this.chainBaseManager = dbManager.getChainBaseManager();
Expand Down Expand Up @@ -72,13 +79,26 @@ public static void start() {
appT.startup();
SolidityNode node = new SolidityNode(appT.getDbManager());
node.run();
appT.blockUntilShutdown();
awaitShutdown(appT, node);
}

@VisibleForTesting
static void awaitShutdown(Application appT, SolidityNode node) {
Comment thread
Sunny6889 marked this conversation as resolved.
try {
appT.blockUntilShutdown();
} finally {
// SolidityNode is created manually rather than managed by Spring/Application,
// so its executors must be shut down explicitly on exit.
node.shutdown();
}
}

private void run() {
try {
new Thread(this::getBlock).start();
new Thread(this::processBlock).start();
getBlockEs = ExecutorServiceManager.newSingleThreadExecutor("solid-get-block");
processBlockEs = ExecutorServiceManager.newSingleThreadExecutor("solid-process-block");
getBlockEs.execute(this::getBlock);
processBlockEs.execute(this::processBlock);
logger.info("Success to start solid node, ID: {}, remoteBlockNum: {}.", ID.get(),
remoteBlockNum);
} catch (Exception e) {
Expand All @@ -88,6 +108,15 @@ private void run() {
}
}

public void shutdown() {
flag = false;
// Signal both pools before awaiting either so they drain concurrently
getBlockEs.shutdown();
processBlockEs.shutdown();
ExecutorServiceManager.shutdownAndAwaitTermination(getBlockEs, "solid-get-block");
Comment thread
Sunny6889 marked this conversation as resolved.
ExecutorServiceManager.shutdownAndAwaitTermination(processBlockEs, "solid-process-block");
}

private void getBlock() {
long blockNum = ID.incrementAndGet();
while (flag) {
Expand Down Expand Up @@ -137,7 +166,7 @@ private void loopProcessBlock(Block block) {
}

private Block getBlockByNum(long blockNum) {
while (true) {
while (flag) {
try {
long time = System.currentTimeMillis();
Block block = databaseGrpcClient.getBlock(blockNum);
Expand All @@ -155,10 +184,11 @@ private Block getBlockByNum(long blockNum) {
sleep(exceptionSleepTime);
}
}
return null;
}

private long getLastSolidityBlockNum() {
while (true) {
while (flag) {
try {
long time = System.currentTimeMillis();
long blockNum = databaseGrpcClient.getDynamicProperties().getLastSolidityBlockNum();
Expand All @@ -171,6 +201,7 @@ private long getLastSolidityBlockNum() {
sleep(exceptionSleepTime);
}
}
return 0;
}

public void sleep(long time) {
Expand All @@ -193,4 +224,4 @@ private void resolveCompatibilityIssueIfUsingFullNodeDatabase() {
chainBaseManager.getDynamicPropertiesStore().saveLatestSolidifiedBlockNum(headBlockNum);
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package org.tron.common;

import io.grpc.ManagedChannel;
import java.util.concurrent.TimeUnit;
import org.tron.common.application.ApplicationFactory;
import org.tron.common.application.TronApplicationContext;
import org.tron.core.config.DefaultConfig;

/**
* Shared class-level fixture for tests that manually manage a TronApplicationContext.
*/
public class ClassLevelAppContextFixture {

private TronApplicationContext context;

public TronApplicationContext createContext() {
context = new TronApplicationContext(DefaultConfig.class);
return context;
}

public TronApplicationContext createAndStart() {
createContext();
startApp();
return context;
}

public void startApp() {
ApplicationFactory.create(context).startup();
}

public TronApplicationContext getContext() {
return context;
}

public void close() {
if (context != null) {
context.close();
context = null;
}
}

public static void shutdownChannel(ManagedChannel channel) {
if (channel == null) {
return;
}
try {
channel.shutdown();
if (!channel.awaitTermination(5, TimeUnit.SECONDS)) {
channel.shutdownNow();
}
} catch (InterruptedException e) {
channel.shutdownNow();
Thread.currentThread().interrupt();
}
}

public static void shutdownChannels(ManagedChannel... channels) {
for (ManagedChannel channel : channels) {
shutdownChannel(channel);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,10 @@ public class BackupServerTest {
@Rule
public TemporaryFolder temporaryFolder = new TemporaryFolder();

// 90s: close() calls channel.close().await(10s) then ESM.shutdownAndAwaitTermination (up to 60s),
// plus 20s headroom for server startup and test body.
@Rule
public Timeout globalTimeout = Timeout.seconds(60);
public Timeout globalTimeout = Timeout.seconds(90);
Comment thread
Sunny6889 marked this conversation as resolved.
private BackupServer backupServer;

@Before
Expand All @@ -43,7 +45,7 @@ public void tearDown() {
Args.clearParam();
}

@Test(timeout = 60_000)
@Test
public void test() throws InterruptedException {
backupServer.initServer();
// wait for the server to start
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,6 @@ public synchronized void testEventParser() {

for (int i = 0; i < entryArr.size(); i++) {
JSONObject e = entryArr.getJSONObject(i);
System.out.println(e.getString("name"));
if (e.getString("name") != null) {
if (e.getString("name").equalsIgnoreCase("eventBytesL")) {
entry = e;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,6 @@ public synchronized void testEventParser() {

ABI.Entry entry = null;
for (ABI.Entry e : abi.getEntrysList()) {
System.out.println(e.getName());
if (e.getName().equalsIgnoreCase("eventBytesL")) {
entry = e;
break;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
package org.tron.common.logsfilter;

import java.util.concurrent.ExecutorService;
import org.junit.After;
import org.junit.Assert;
import org.junit.Test;
import org.tron.common.es.ExecutorServiceManager;
import org.tron.common.logsfilter.nativequeue.NativeMessageQueue;
import org.zeromq.SocketType;
import org.zeromq.ZContext;
Expand All @@ -13,6 +16,15 @@ public class NativeMessageQueueTest {
public String dataToSend = "################";
public String topic = "testTopic";

private ExecutorService subscriberExecutor;
private final String zmqSubscriber = "zmq-subscriber";

@After
public void tearDown() {
ExecutorServiceManager.shutdownAndAwaitTermination(subscriberExecutor, zmqSubscriber);
subscriberExecutor = null;
}

@Test
public void invalidBindPort() {
boolean bRet = NativeMessageQueue.getInstance().start(-1111, 0);
Expand All @@ -39,22 +51,23 @@ public void publishTrigger() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
Thread.currentThread().interrupt();
}

NativeMessageQueue.getInstance().publishTrigger(dataToSend, topic);

try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
Thread.currentThread().interrupt();
}

NativeMessageQueue.getInstance().stop();
}

public void startSubscribeThread() {
Thread thread = new Thread(() -> {
subscriberExecutor = ExecutorServiceManager.newSingleThreadExecutor(zmqSubscriber);
subscriberExecutor.execute(() -> {
try (ZContext context = new ZContext()) {
ZMQ.Socket subscriber = context.createSocket(SocketType.SUB);

Expand All @@ -70,6 +83,5 @@ public void startSubscribeThread() {
// ZMQ.Socket will be automatically closed when ZContext is closed
}
});
thread.start();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ public void setUp() {
public void testSetAndGetBlockHash() {
blockFilterCapsule
.setBlockHash("e58f33f9baf9305dc6f82b9f1934ea8f0ade2defb951258d50167028c780351f");
System.out.println(blockFilterCapsule);
Assert.assertEquals("e58f33f9baf9305dc6f82b9f1934ea8f0ade2defb951258d50167028c780351f",
blockFilterCapsule.getBlockHash());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import org.junit.BeforeClass;
import org.junit.Test;
import org.tron.common.BaseTest;
import org.tron.common.parameter.CommonParameter;
import org.tron.common.runtime.RuntimeImpl;
import org.tron.common.runtime.TvmTestUtils;
import org.tron.common.utils.Commons;
Expand Down Expand Up @@ -153,8 +154,13 @@ public void testSuccess() {

@Test
public void testSuccessNoBandd() {
boolean originalDebug = CommonParameter.getInstance().isDebug();
try {
byte[] contractAddress = createContract();
// Enable debug mode to bypass CPU time limit check in Program.checkCPUTimeLimit().
// Without this, the heavy contract execution (setCoin) may exceed the time threshold
// on slow machines and cause the test to fail non-deterministically.
CommonParameter.getInstance().setDebug(true);
TriggerSmartContract triggerContract = TvmTestUtils.createTriggerContract(contractAddress,
"setCoin(uint256)", "50", false,
0, Commons.decodeFromBase58Check(TriggerOwnerTwoAddress));
Expand Down Expand Up @@ -185,6 +191,8 @@ public void testSuccessNoBandd() {
balance);
} catch (TronException e) {
Assert.assertNotNull(e);
} finally {
CommonParameter.getInstance().setDebug(originalDebug);
}
}

Expand Down Expand Up @@ -254,4 +262,4 @@ public void testMaxContractResultSize() {
}
Assert.assertEquals(2, maxSize);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -289,17 +289,9 @@ public void testWithCallerEnergyChangedInTx() throws Exception {

TVMTestResult result = freezeForOther(userA, contractAddr, userA, frozenBalance, 1);

System.out.println(result.getReceipt().getEnergyUsageTotal());
System.out.println(accountStore.get(userA));
System.out.println(accountStore.get(owner));

clearDelegatedExpireTime(contractAddr, userA);

result = unfreezeForOther(userA, contractAddr, userA, 1);

System.out.println(result.getReceipt().getEnergyUsageTotal());
System.out.println(accountStore.get(userA));
System.out.println(accountStore.get(owner));
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -124,8 +124,6 @@ public void testZeroLengthOneArray() {
// witness array zero, amount array non-zero
Program program = mockProgram(0, 0, 64, 1, 0);
long cost = EnergyCost.getVoteWitnessCost3(program);
// witnessArraySize = 0 * 32 + 32 = 32, witnessMemNeeded = 0 + 32 = 32
// amountArraySize = 1 * 32 + 32 = 64, amountMemNeeded = 64 + 64 = 128
// memWords = 128 / 32 = 4
// memEnergy = 3 * 4 + 4 * 4 / 512 = 12
assertEquals(30012, cost);
Expand Down
Loading
Loading