Skip to content

Commit 7de0f2a

Browse files
317787106claude
andcommitted
feat(framework): refactor SolidityNode as Spring component with safe shutdown
- Convert SolidityNode from static utility to @conditional @component so it only registers when --solidity is passed - Implement ApplicationListener<ContextClosedEvent> to set flag=false before any @PreDestroy method fires, stopping worker threads promptly - Add pushVerifiedBlock() to TronNetDelegate to route solidity sync blocks through the conditional-shutdown check (<=, not ==, because a single batch write can advance the DB header past the target number) - Guard saveLatestSolidifiedBlockNum in loopProcessBlock: skip the write when hitDown is true, preventing a phantom block-num from persisting when the block was never actually pushed to BlockStore - Add unit tests covering lifecycle hooks, all retry paths, interrupt handling, and the hitDown save-guard; SolidityNode line coverage 28% -> 81% Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 1a97a81 commit 7de0f2a

7 files changed

Lines changed: 884 additions & 338 deletions

File tree

framework/src/main/java/org/tron/core/db/Manager.java

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1033,23 +1033,6 @@ public void eraseBlock() {
10331033
}
10341034
}
10351035

1036-
public void pushVerifiedBlock(BlockCapsule block) throws ContractValidateException,
1037-
ContractExeException, ValidateSignatureException, AccountResourceInsufficientException,
1038-
TransactionExpirationException, TooBigTransactionException, DupTransactionException,
1039-
TaposException, ValidateScheduleException, ReceiptCheckErrException,
1040-
VMIllegalException, TooBigTransactionResultException, UnLinkedBlockException,
1041-
NonCommonBlockException, BadNumberBlockException, BadBlockException, ZksnarkException,
1042-
EventBloomException {
1043-
block.generatedByMyself = true;
1044-
long start = System.currentTimeMillis();
1045-
pushBlock(block);
1046-
logger.info("Push block cost: {} ms, blockNum: {}, blockHash: {}, trx count: {}.",
1047-
System.currentTimeMillis() - start,
1048-
block.getNum(),
1049-
block.getBlockId(),
1050-
block.getTransactions().size());
1051-
}
1052-
10531036
private void applyBlock(BlockCapsule block) throws ContractValidateException,
10541037
ContractExeException, ValidateSignatureException, AccountResourceInsufficientException,
10551038
TransactionExpirationException, TooBigTransactionException, DupTransactionException,

framework/src/main/java/org/tron/core/net/TronNetDelegate.java

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -233,9 +233,25 @@ public Message getData(Sha256Hash hash, InventoryType type) throws P2pException
233233
}
234234
}
235235

236+
public void pushVerifiedBlock(BlockCapsule block) throws P2pException {
237+
block.generatedByMyself = true;
238+
long start = System.currentTimeMillis();
239+
processBlock(block, true);
240+
if (!hitDown) {
241+
logger.info("Push block cost: {} ms, blockNum: {}, blockHash: {}, trx count: {}.",
242+
System.currentTimeMillis() - start,
243+
block.getNum(),
244+
block.getBlockId(),
245+
block.getTransactions().size());
246+
}
247+
}
248+
236249
public void processBlock(BlockCapsule block, boolean isSync) throws P2pException {
250+
// Use <= rather than == because pushBlock may commit multiple blocks in a single
251+
// batch write, causing the DB header number to jump past the target block number
252+
// and never equal it exactly.
237253
if (!hitDown && dbManager.getLatestSolidityNumShutDown() > 0
238-
&& dbManager.getLatestSolidityNumShutDown() == dbManager.getDynamicPropertiesStore()
254+
&& dbManager.getLatestSolidityNumShutDown() <= dbManager.getDynamicPropertiesStore()
239255
.getLatestBlockHeaderNumberFromDB()) {
240256

241257
logger.info("Begin shutdown, currentBlockNum:{}, DbBlockNum:{}, solidifiedBlockNum:{}",

framework/src/main/java/org/tron/program/FullNode.java

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import lombok.extern.slf4j.Slf4j;
44
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
5+
import org.springframework.util.ObjectUtils;
56
import org.tron.common.application.Application;
67
import org.tron.common.application.ApplicationFactory;
78
import org.tron.common.application.TronApplicationContext;
@@ -28,19 +29,24 @@ public static void main(String[] args) {
2829

2930
LogService.load(parameter.getLogbackPath());
3031

31-
if (parameter.isSolidityNode()) {
32-
SolidityNode.start();
33-
return;
34-
}
3532
if (parameter.isKeystoreFactory()) {
3633
KeystoreFactory.start();
3734
return;
3835
}
39-
logger.info("Full node running.");
40-
if (Args.getInstance().isDebug()) {
41-
logger.info("in debug mode, it won't check energy time");
36+
if (parameter.isSolidityNode()) {
37+
logger.info("Solidity node is running.");
38+
if (ObjectUtils.isEmpty(parameter.getTrustNodeAddr())) {
39+
throw new TronError(new IllegalArgumentException("Trust node is not set."),
40+
TronError.ErrCode.SOLID_NODE_INIT);
41+
}
42+
parameter.setP2pDisable(true);
4243
} else {
43-
logger.info("not in debug mode, it will check energy time");
44+
logger.info("Full node running.");
45+
if (Args.getInstance().isDebug()) {
46+
logger.info("in debug mode, it won't check energy time");
47+
} else {
48+
logger.info("not in debug mode, it will check energy time");
49+
}
4450
}
4551

4652
// init metrics first
@@ -55,6 +61,10 @@ public static void main(String[] args) {
5561
Application appT = ApplicationFactory.create(context);
5662
context.registerShutdownHook();
5763
appT.startup();
64+
if (parameter.isSolidityNode()) {
65+
SolidityNode node = context.getBean(SolidityNode.class);
66+
node.run();
67+
}
5868
appT.blockUntilShutdown();
5969
}
6070

0 commit comments

Comments
 (0)