From 4101be43bf782d916aeb95d2d24383d29546841b Mon Sep 17 00:00:00 2001 From: jiangyuanshu <317787106@qq.com> Date: Fri, 30 Jan 2026 18:49:10 +0800 Subject: [PATCH 1/7] support shutdown for SolidityNode --- .../main/java/org/tron/core/db/Manager.java | 17 ---- .../org/tron/core/net/TronNetDelegate.java | 17 ++++ .../main/java/org/tron/program/FullNode.java | 25 +++-- .../java/org/tron/program/SolidityNode.java | 94 ++++++++++--------- .../java/org/tron/core/db/ManagerTest.java | 12 +-- .../org/tron/program/SolidityNodeTest.java | 22 ++--- 6 files changed, 101 insertions(+), 86 deletions(-) diff --git a/framework/src/main/java/org/tron/core/db/Manager.java b/framework/src/main/java/org/tron/core/db/Manager.java index cd1a61c01fe..cc3e5d0c0e9 100644 --- a/framework/src/main/java/org/tron/core/db/Manager.java +++ b/framework/src/main/java/org/tron/core/db/Manager.java @@ -1033,23 +1033,6 @@ public void eraseBlock() { } } - public void pushVerifiedBlock(BlockCapsule block) throws ContractValidateException, - ContractExeException, ValidateSignatureException, AccountResourceInsufficientException, - TransactionExpirationException, TooBigTransactionException, DupTransactionException, - TaposException, ValidateScheduleException, ReceiptCheckErrException, - VMIllegalException, TooBigTransactionResultException, UnLinkedBlockException, - NonCommonBlockException, BadNumberBlockException, BadBlockException, ZksnarkException, - EventBloomException { - block.generatedByMyself = true; - long start = System.currentTimeMillis(); - pushBlock(block); - logger.info("Push block cost: {} ms, blockNum: {}, blockHash: {}, trx count: {}.", - System.currentTimeMillis() - start, - block.getNum(), - block.getBlockId(), - block.getTransactions().size()); - } - private void applyBlock(BlockCapsule block) throws ContractValidateException, ContractExeException, ValidateSignatureException, AccountResourceInsufficientException, TransactionExpirationException, TooBigTransactionException, DupTransactionException, diff --git a/framework/src/main/java/org/tron/core/net/TronNetDelegate.java b/framework/src/main/java/org/tron/core/net/TronNetDelegate.java index 100bad179bf..f3bcf0d45bf 100644 --- a/framework/src/main/java/org/tron/core/net/TronNetDelegate.java +++ b/framework/src/main/java/org/tron/core/net/TronNetDelegate.java @@ -233,6 +233,23 @@ public Message getData(Sha256Hash hash, InventoryType type) throws P2pException } } + public void pushVerifiedBlock(BlockCapsule block) throws ContractValidateException, + ContractExeException, ValidateSignatureException, AccountResourceInsufficientException, + TransactionExpirationException, TooBigTransactionException, DupTransactionException, + TaposException, ValidateScheduleException, ReceiptCheckErrException, + VMIllegalException, TooBigTransactionResultException, UnLinkedBlockException, + NonCommonBlockException, BadNumberBlockException, BadBlockException, ZksnarkException, + EventBloomException { + block.generatedByMyself = true; + long start = System.currentTimeMillis(); + dbManager.pushBlock(block); + logger.info("Push block cost: {} ms, blockNum: {}, blockHash: {}, trx count: {}.", + System.currentTimeMillis() - start, + block.getNum(), + block.getBlockId(), + block.getTransactions().size()); + } + public void processBlock(BlockCapsule block, boolean isSync) throws P2pException { if (!hitDown && dbManager.getLatestSolidityNumShutDown() > 0 && dbManager.getLatestSolidityNumShutDown() == dbManager.getDynamicPropertiesStore() diff --git a/framework/src/main/java/org/tron/program/FullNode.java b/framework/src/main/java/org/tron/program/FullNode.java index 95257d77f8e..308cb9a1c69 100644 --- a/framework/src/main/java/org/tron/program/FullNode.java +++ b/framework/src/main/java/org/tron/program/FullNode.java @@ -2,6 +2,7 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.support.DefaultListableBeanFactory; +import org.springframework.util.ObjectUtils; import org.tron.common.application.Application; import org.tron.common.application.ApplicationFactory; import org.tron.common.application.TronApplicationContext; @@ -28,19 +29,23 @@ public static void main(String[] args) { LogService.load(parameter.getLogbackPath()); - if (parameter.isSolidityNode()) { - SolidityNode.start(); - return; - } if (parameter.isKeystoreFactory()) { KeystoreFactory.start(); return; } - logger.info("Full node running."); - if (Args.getInstance().isDebug()) { - logger.info("in debug mode, it won't check energy time"); + if (parameter.isSolidityNode()) { + logger.info("Solidity node is running."); + if (ObjectUtils.isEmpty(parameter.getTrustNodeAddr())) { + throw new TronError(new IllegalArgumentException("Trust node is not set."), + TronError.ErrCode.SOLID_NODE_INIT); + } } else { - logger.info("not in debug mode, it will check energy time"); + logger.info("Full node running."); + if (Args.getInstance().isDebug()) { + logger.info("in debug mode, it won't check energy time"); + } else { + logger.info("not in debug mode, it will check energy time"); + } } // init metrics first @@ -55,6 +60,10 @@ public static void main(String[] args) { Application appT = ApplicationFactory.create(context); context.registerShutdownHook(); appT.startup(); + if (parameter.isSolidityNode()) { + SolidityNode node = context.getBean(SolidityNode.class); + node.run(); + } appT.blockUntilShutdown(); } diff --git a/framework/src/main/java/org/tron/program/SolidityNode.java b/framework/src/main/java/org/tron/program/SolidityNode.java index 3367141e2a5..2698beee899 100644 --- a/framework/src/main/java/org/tron/program/SolidityNode.java +++ b/framework/src/main/java/org/tron/program/SolidityNode.java @@ -2,83 +2,82 @@ import static org.tron.core.config.Parameter.ChainConstant.BLOCK_PRODUCED_INTERVAL; +import java.util.concurrent.ExecutorService; import java.util.concurrent.LinkedBlockingDeque; import java.util.concurrent.atomic.AtomicLong; +import javax.annotation.PostConstruct; +import javax.annotation.PreDestroy; import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.factory.support.DefaultListableBeanFactory; -import org.springframework.util.ObjectUtils; -import org.tron.common.application.Application; -import org.tron.common.application.ApplicationFactory; -import org.tron.common.application.TronApplicationContext; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Condition; +import org.springframework.context.annotation.ConditionContext; +import org.springframework.context.annotation.Conditional; +import org.springframework.core.type.AnnotatedTypeMetadata; +import org.springframework.stereotype.Component; 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; import org.tron.core.capsule.BlockCapsule; -import org.tron.core.config.DefaultConfig; -import org.tron.core.db.Manager; +import org.tron.core.config.args.Args; import org.tron.core.exception.TronError; +import org.tron.core.net.TronNetDelegate; import org.tron.protos.Protocol.Block; @Slf4j(topic = "app") +@Conditional(value = {SolidityNode.SolidityCondition.class}) +@Component public class SolidityNode { - private Manager dbManager; - + @Autowired private ChainBaseManager chainBaseManager; + @Autowired + private TronNetDelegate tronNetDelegate; + private DatabaseGrpcClient databaseGrpcClient; private AtomicLong ID = new AtomicLong(); - private AtomicLong remoteBlockNum = new AtomicLong(); + private final AtomicLong remoteBlockNum = new AtomicLong(); - private LinkedBlockingDeque blockQueue = new LinkedBlockingDeque<>(100); + private final LinkedBlockingDeque blockQueue = new LinkedBlockingDeque<>(100); - private int exceptionSleepTime = 1000; + private final int exceptionSleepTime = 1000; private volatile boolean flag = true; - public SolidityNode(Manager dbManager) { - this.dbManager = dbManager; - this.chainBaseManager = dbManager.getChainBaseManager(); + private final String getBlockName = "get-block"; + private final String processBlockName = "process-block"; + + private ExecutorService getBlockExecutor; + private ExecutorService processBlockExecutor; + + @PostConstruct + private void init() { resolveCompatibilityIssueIfUsingFullNodeDatabase(); ID.set(chainBaseManager.getDynamicPropertiesStore().getLatestSolidifiedBlockNum()); databaseGrpcClient = new DatabaseGrpcClient(CommonParameter.getInstance().getTrustNodeAddr()); remoteBlockNum.set(getLastSolidityBlockNum()); + + getBlockExecutor = ExecutorServiceManager.newSingleThreadExecutor(getBlockName); + processBlockExecutor = ExecutorServiceManager.newSingleThreadExecutor(processBlockName); } - /** - * Start the SolidityNode. - */ - public static void start() { - logger.info("Solidity node is running."); - CommonParameter parameter = CommonParameter.getInstance(); - if (ObjectUtils.isEmpty(parameter.getTrustNodeAddr())) { - throw new TronError(new IllegalArgumentException("Trust node is not set."), - TronError.ErrCode.SOLID_NODE_INIT); + @PreDestroy + private void shutdown() { + flag = false; + ExecutorServiceManager.shutdownAndAwaitTermination(getBlockExecutor, getBlockName); + ExecutorServiceManager.shutdownAndAwaitTermination(processBlockExecutor, processBlockName); + if (databaseGrpcClient != null) { + databaseGrpcClient.shutdown(); } - // init metrics first - Metrics.init(); - - DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory(); - beanFactory.setAllowCircularReferences(false); - TronApplicationContext context = - new TronApplicationContext(beanFactory); - context.register(DefaultConfig.class); - context.refresh(); - Application appT = ApplicationFactory.create(context); - context.registerShutdownHook(); - appT.startup(); - SolidityNode node = new SolidityNode(appT.getDbManager()); - node.run(); - appT.blockUntilShutdown(); } - private void run() { + public void run() { try { - new Thread(this::getBlock).start(); - new Thread(this::processBlock).start(); + getBlockExecutor.submit(this::getBlock); + processBlockExecutor.submit(this::processBlock); logger.info("Success to start solid node, ID: {}, remoteBlockNum: {}.", ID.get(), remoteBlockNum); } catch (Exception e) { @@ -123,7 +122,7 @@ private void loopProcessBlock(Block block) { while (flag) { long blockNum = block.getBlockHeader().getRawData().getNumber(); try { - dbManager.pushVerifiedBlock(new BlockCapsule(block)); + tronNetDelegate.pushVerifiedBlock(new BlockCapsule(block)); chainBaseManager.getDynamicPropertiesStore().saveLatestSolidifiedBlockNum(blockNum); logger .info("Success to process block: {}, blockQueueSize: {}.", blockNum, blockQueue.size()); @@ -193,4 +192,11 @@ private void resolveCompatibilityIssueIfUsingFullNodeDatabase() { chainBaseManager.getDynamicPropertiesStore().saveLatestSolidifiedBlockNum(headBlockNum); } } + + static class SolidityCondition implements Condition { + @Override + public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { + return Args.getInstance().isSolidityNode(); + } + } } \ No newline at end of file diff --git a/framework/src/test/java/org/tron/core/db/ManagerTest.java b/framework/src/test/java/org/tron/core/db/ManagerTest.java index b9808b89193..9bb4a88f4a4 100755 --- a/framework/src/test/java/org/tron/core/db/ManagerTest.java +++ b/framework/src/test/java/org/tron/core/db/ManagerTest.java @@ -314,12 +314,12 @@ public void transactionTest() { } catch (Exception e) { Assert.assertTrue(e instanceof TaposException); } - try { - dbManager.pushVerifiedBlock(chainManager.getHead()); - dbManager.getBlockChainHashesOnFork(chainManager.getHeadBlockId()); - } catch (Exception e) { - Assert.assertTrue(e instanceof TaposException); - } +// try { +// dbManager.pushVerifiedBlock(chainManager.getHead()); +// dbManager.getBlockChainHashesOnFork(chainManager.getHeadBlockId()); +// } catch (Exception e) { +// Assert.assertTrue(e instanceof TaposException); +// } } @Test diff --git a/framework/src/test/java/org/tron/program/SolidityNodeTest.java b/framework/src/test/java/org/tron/program/SolidityNodeTest.java index 7d94f813b80..40345e863b7 100755 --- a/framework/src/test/java/org/tron/program/SolidityNodeTest.java +++ b/framework/src/test/java/org/tron/program/SolidityNodeTest.java @@ -40,17 +40,17 @@ public class SolidityNodeTest extends BaseTest { Args.getInstance().setSolidityHttpPort(solidityHttpPort); } - @Test - public void testSolidityArgs() { - Assert.assertNotNull(Args.getInstance().getTrustNodeAddr()); - Assert.assertTrue(Args.getInstance().isSolidityNode()); - String trustNodeAddr = Args.getInstance().getTrustNodeAddr(); - Args.getInstance().setTrustNodeAddr(null); - TronError thrown = assertThrows(TronError.class, - SolidityNode::start); - assertEquals(TronError.ErrCode.SOLID_NODE_INIT, thrown.getErrCode()); - Args.getInstance().setTrustNodeAddr(trustNodeAddr); - } +// @Test +// public void testSolidityArgs() { +// Assert.assertNotNull(Args.getInstance().getTrustNodeAddr()); +// Assert.assertTrue(Args.getInstance().isSolidityNode()); +// String trustNodeAddr = Args.getInstance().getTrustNodeAddr(); +// Args.getInstance().setTrustNodeAddr(null); +// TronError thrown = assertThrows(TronError.class, +// SolidityNode::start); +// assertEquals(TronError.ErrCode.SOLID_NODE_INIT, thrown.getErrCode()); +// Args.getInstance().setTrustNodeAddr(trustNodeAddr); +// } @Test public void testSolidityGrpcCall() { From 8895b7b0d1ab9be79df014f13f39e076da9a7c56 Mon Sep 17 00:00:00 2001 From: jiangyuanshu <317787106@qq.com> Date: Mon, 2 Feb 2026 11:30:04 +0800 Subject: [PATCH 2/7] disable p2p --- framework/src/main/java/org/tron/program/FullNode.java | 1 + 1 file changed, 1 insertion(+) diff --git a/framework/src/main/java/org/tron/program/FullNode.java b/framework/src/main/java/org/tron/program/FullNode.java index 308cb9a1c69..a7d204de025 100644 --- a/framework/src/main/java/org/tron/program/FullNode.java +++ b/framework/src/main/java/org/tron/program/FullNode.java @@ -39,6 +39,7 @@ public static void main(String[] args) { throw new TronError(new IllegalArgumentException("Trust node is not set."), TronError.ErrCode.SOLID_NODE_INIT); } + parameter.setP2pDisable(true); } else { logger.info("Full node running."); if (Args.getInstance().isDebug()) { From 62107e6cc7ab6d133231ad6af18212a7007b78c7 Mon Sep 17 00:00:00 2001 From: jiangyuanshu <317787106@qq.com> Date: Mon, 2 Feb 2026 12:50:16 +0800 Subject: [PATCH 3/7] optimize pushVerifiedBlock --- .../main/java/org/tron/core/net/TronNetDelegate.java | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/framework/src/main/java/org/tron/core/net/TronNetDelegate.java b/framework/src/main/java/org/tron/core/net/TronNetDelegate.java index f3bcf0d45bf..4fcdfc5e667 100644 --- a/framework/src/main/java/org/tron/core/net/TronNetDelegate.java +++ b/framework/src/main/java/org/tron/core/net/TronNetDelegate.java @@ -233,16 +233,10 @@ public Message getData(Sha256Hash hash, InventoryType type) throws P2pException } } - public void pushVerifiedBlock(BlockCapsule block) throws ContractValidateException, - ContractExeException, ValidateSignatureException, AccountResourceInsufficientException, - TransactionExpirationException, TooBigTransactionException, DupTransactionException, - TaposException, ValidateScheduleException, ReceiptCheckErrException, - VMIllegalException, TooBigTransactionResultException, UnLinkedBlockException, - NonCommonBlockException, BadNumberBlockException, BadBlockException, ZksnarkException, - EventBloomException { + public void pushVerifiedBlock(BlockCapsule block) throws P2pException { block.generatedByMyself = true; long start = System.currentTimeMillis(); - dbManager.pushBlock(block); + processBlock(block, true); logger.info("Push block cost: {} ms, blockNum: {}, blockHash: {}, trx count: {}.", System.currentTimeMillis() - start, block.getNum(), From 0e5a48f84db428687617ec5d1bef59c5526cc8aa Mon Sep 17 00:00:00 2001 From: jiangyuanshu <317787106@qq.com> Date: Wed, 22 Apr 2026 11:32:17 +0800 Subject: [PATCH 4/7] use flag in getBlockByNum, getLastSolidityBlockNum --- .../src/main/java/org/tron/program/SolidityNode.java | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/framework/src/main/java/org/tron/program/SolidityNode.java b/framework/src/main/java/org/tron/program/SolidityNode.java index 2698beee899..126ec31a152 100644 --- a/framework/src/main/java/org/tron/program/SolidityNode.java +++ b/framework/src/main/java/org/tron/program/SolidityNode.java @@ -37,7 +37,7 @@ public class SolidityNode { private DatabaseGrpcClient databaseGrpcClient; - private AtomicLong ID = new AtomicLong(); + private final AtomicLong ID = new AtomicLong(); private final AtomicLong remoteBlockNum = new AtomicLong(); @@ -136,7 +136,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); @@ -154,10 +154,11 @@ private Block getBlockByNum(long blockNum) { sleep(exceptionSleepTime); } } + throw new RuntimeException("SolitityNode is closing."); } private long getLastSolidityBlockNum() { - while (true) { + while (flag) { try { long time = System.currentTimeMillis(); long blockNum = databaseGrpcClient.getDynamicProperties().getLastSolidityBlockNum(); @@ -170,6 +171,7 @@ private long getLastSolidityBlockNum() { sleep(exceptionSleepTime); } } + throw new RuntimeException("SolitityNode is closing."); } public void sleep(long time) { From 18cbc166a91e3581040433eab239ea466f89630b Mon Sep 17 00:00:00 2001 From: jiangyuanshu <317787106@qq.com> Date: Thu, 23 Apr 2026 18:19:10 +0800 Subject: [PATCH 5/7] delete invalid testcase --- .../src/test/java/org/tron/core/db/ManagerTest.java | 6 ------ .../test/java/org/tron/program/SolidityNodeTest.java | 12 ------------ 2 files changed, 18 deletions(-) diff --git a/framework/src/test/java/org/tron/core/db/ManagerTest.java b/framework/src/test/java/org/tron/core/db/ManagerTest.java index 9bb4a88f4a4..e7c337723a5 100755 --- a/framework/src/test/java/org/tron/core/db/ManagerTest.java +++ b/framework/src/test/java/org/tron/core/db/ManagerTest.java @@ -314,12 +314,6 @@ public void transactionTest() { } catch (Exception e) { Assert.assertTrue(e instanceof TaposException); } -// try { -// dbManager.pushVerifiedBlock(chainManager.getHead()); -// dbManager.getBlockChainHashesOnFork(chainManager.getHeadBlockId()); -// } catch (Exception e) { -// Assert.assertTrue(e instanceof TaposException); -// } } @Test diff --git a/framework/src/test/java/org/tron/program/SolidityNodeTest.java b/framework/src/test/java/org/tron/program/SolidityNodeTest.java index 40345e863b7..5cfdec41ebf 100755 --- a/framework/src/test/java/org/tron/program/SolidityNodeTest.java +++ b/framework/src/test/java/org/tron/program/SolidityNodeTest.java @@ -40,18 +40,6 @@ public class SolidityNodeTest extends BaseTest { Args.getInstance().setSolidityHttpPort(solidityHttpPort); } -// @Test -// public void testSolidityArgs() { -// Assert.assertNotNull(Args.getInstance().getTrustNodeAddr()); -// Assert.assertTrue(Args.getInstance().isSolidityNode()); -// String trustNodeAddr = Args.getInstance().getTrustNodeAddr(); -// Args.getInstance().setTrustNodeAddr(null); -// TronError thrown = assertThrows(TronError.class, -// SolidityNode::start); -// assertEquals(TronError.ErrCode.SOLID_NODE_INIT, thrown.getErrCode()); -// Args.getInstance().setTrustNodeAddr(trustNodeAddr); -// } - @Test public void testSolidityGrpcCall() { rpcApiService.start(); From 50c76de878e421ae2215e79ebaa2501f820565db Mon Sep 17 00:00:00 2001 From: jiangyuanshu <317787106@qq.com> Date: Sat, 25 Apr 2026 11:41:36 +0800 Subject: [PATCH 6/7] format the code --- .../java/org/tron/program/SolidityNode.java | 406 +++++++++--------- 1 file changed, 203 insertions(+), 203 deletions(-) diff --git a/framework/src/main/java/org/tron/program/SolidityNode.java b/framework/src/main/java/org/tron/program/SolidityNode.java index 126ec31a152..78144311f81 100644 --- a/framework/src/main/java/org/tron/program/SolidityNode.java +++ b/framework/src/main/java/org/tron/program/SolidityNode.java @@ -1,204 +1,204 @@ -package org.tron.program; - -import static org.tron.core.config.Parameter.ChainConstant.BLOCK_PRODUCED_INTERVAL; - -import java.util.concurrent.ExecutorService; -import java.util.concurrent.LinkedBlockingDeque; -import java.util.concurrent.atomic.AtomicLong; -import javax.annotation.PostConstruct; -import javax.annotation.PreDestroy; -import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.annotation.Condition; -import org.springframework.context.annotation.ConditionContext; -import org.springframework.context.annotation.Conditional; -import org.springframework.core.type.AnnotatedTypeMetadata; -import org.springframework.stereotype.Component; -import org.tron.common.client.DatabaseGrpcClient; -import org.tron.common.es.ExecutorServiceManager; -import org.tron.common.parameter.CommonParameter; -import org.tron.core.ChainBaseManager; -import org.tron.core.capsule.BlockCapsule; -import org.tron.core.config.args.Args; -import org.tron.core.exception.TronError; -import org.tron.core.net.TronNetDelegate; -import org.tron.protos.Protocol.Block; - -@Slf4j(topic = "app") -@Conditional(value = {SolidityNode.SolidityCondition.class}) -@Component -public class SolidityNode { - - @Autowired - private ChainBaseManager chainBaseManager; - - @Autowired - private TronNetDelegate tronNetDelegate; - - private DatabaseGrpcClient databaseGrpcClient; - - private final AtomicLong ID = new AtomicLong(); - - private final AtomicLong remoteBlockNum = new AtomicLong(); - - private final LinkedBlockingDeque blockQueue = new LinkedBlockingDeque<>(100); - - private final int exceptionSleepTime = 1000; - - private volatile boolean flag = true; - - private final String getBlockName = "get-block"; - private final String processBlockName = "process-block"; - - private ExecutorService getBlockExecutor; - private ExecutorService processBlockExecutor; - - @PostConstruct - private void init() { - resolveCompatibilityIssueIfUsingFullNodeDatabase(); - ID.set(chainBaseManager.getDynamicPropertiesStore().getLatestSolidifiedBlockNum()); - databaseGrpcClient = new DatabaseGrpcClient(CommonParameter.getInstance().getTrustNodeAddr()); - remoteBlockNum.set(getLastSolidityBlockNum()); - - getBlockExecutor = ExecutorServiceManager.newSingleThreadExecutor(getBlockName); - processBlockExecutor = ExecutorServiceManager.newSingleThreadExecutor(processBlockName); - } - - @PreDestroy - private void shutdown() { - flag = false; - ExecutorServiceManager.shutdownAndAwaitTermination(getBlockExecutor, getBlockName); - ExecutorServiceManager.shutdownAndAwaitTermination(processBlockExecutor, processBlockName); - if (databaseGrpcClient != null) { - databaseGrpcClient.shutdown(); - } - } - - public void run() { - try { - getBlockExecutor.submit(this::getBlock); - processBlockExecutor.submit(this::processBlock); - logger.info("Success to start solid node, ID: {}, remoteBlockNum: {}.", ID.get(), - remoteBlockNum); - } catch (Exception e) { - logger.error("Failed to start solid node, address: {}.", - CommonParameter.getInstance().getTrustNodeAddr()); - throw new TronError(e, TronError.ErrCode.SOLID_NODE_INIT); - } - } - - private void getBlock() { - long blockNum = ID.incrementAndGet(); - while (flag) { - try { - if (blockNum > remoteBlockNum.get()) { - sleep(BLOCK_PRODUCED_INTERVAL); - remoteBlockNum.set(getLastSolidityBlockNum()); - continue; - } - Block block = getBlockByNum(blockNum); - blockQueue.put(block); - blockNum = ID.incrementAndGet(); - } catch (Exception e) { - logger.error("Failed to get block {}, reason: {}.", blockNum, e.getMessage()); - sleep(exceptionSleepTime); - } - } - } - - private void processBlock() { - while (flag) { - try { - Block block = blockQueue.take(); - loopProcessBlock(block); - } catch (Exception e) { - logger.error(e.getMessage()); - sleep(exceptionSleepTime); - } - } - } - - private void loopProcessBlock(Block block) { - while (flag) { - long blockNum = block.getBlockHeader().getRawData().getNumber(); - try { - tronNetDelegate.pushVerifiedBlock(new BlockCapsule(block)); - chainBaseManager.getDynamicPropertiesStore().saveLatestSolidifiedBlockNum(blockNum); - logger - .info("Success to process block: {}, blockQueueSize: {}.", blockNum, blockQueue.size()); - return; - } catch (Exception e) { - logger.error("Failed to process block {}.", new BlockCapsule(block), e); - sleep(exceptionSleepTime); - block = getBlockByNum(blockNum); - } - } - } - - private Block getBlockByNum(long blockNum) { - while (flag) { - try { - long time = System.currentTimeMillis(); - Block block = databaseGrpcClient.getBlock(blockNum); - long num = block.getBlockHeader().getRawData().getNumber(); - if (num == blockNum) { - logger.info("Success to get block: {}, cost: {}ms.", - blockNum, System.currentTimeMillis() - time); - return block; - } else { - logger.warn("Get block id not the same , {}, {}.", num, blockNum); - sleep(exceptionSleepTime); - } - } catch (Exception e) { - logger.error("Failed to get block: {}, reason: {}.", blockNum, e.getMessage()); - sleep(exceptionSleepTime); - } - } - throw new RuntimeException("SolitityNode is closing."); - } - - private long getLastSolidityBlockNum() { - while (flag) { - try { - long time = System.currentTimeMillis(); - long blockNum = databaseGrpcClient.getDynamicProperties().getLastSolidityBlockNum(); - logger.info("Get last remote solid blockNum: {}, remoteBlockNum: {}, cost: {}.", - blockNum, remoteBlockNum, System.currentTimeMillis() - time); - return blockNum; - } catch (Exception e) { - logger.error("Failed to get last solid blockNum: {}, reason: {}.", remoteBlockNum.get(), - e.getMessage()); - sleep(exceptionSleepTime); - } - } - throw new RuntimeException("SolitityNode is closing."); - } - - public void sleep(long time) { - try { - Thread.sleep(time); - } catch (Exception e1) { - logger.error(e1.getMessage()); - } - } - - private void resolveCompatibilityIssueIfUsingFullNodeDatabase() { - long lastSolidityBlockNum = - chainBaseManager.getDynamicPropertiesStore().getLatestSolidifiedBlockNum(); - long headBlockNum = chainBaseManager.getHeadBlockNum(); - logger.info("headBlockNum:{}, solidityBlockNum:{}, diff:{}", - headBlockNum, lastSolidityBlockNum, headBlockNum - lastSolidityBlockNum); - if (lastSolidityBlockNum < headBlockNum) { - logger.info("use fullNode database, headBlockNum:{}, solidityBlockNum:{}, diff:{}", - headBlockNum, lastSolidityBlockNum, headBlockNum - lastSolidityBlockNum); - chainBaseManager.getDynamicPropertiesStore().saveLatestSolidifiedBlockNum(headBlockNum); - } - } - - static class SolidityCondition implements Condition { - @Override - public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { - return Args.getInstance().isSolidityNode(); - } - } +package org.tron.program; + +import static org.tron.core.config.Parameter.ChainConstant.BLOCK_PRODUCED_INTERVAL; + +import java.util.concurrent.ExecutorService; +import java.util.concurrent.LinkedBlockingDeque; +import java.util.concurrent.atomic.AtomicLong; +import javax.annotation.PostConstruct; +import javax.annotation.PreDestroy; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Condition; +import org.springframework.context.annotation.ConditionContext; +import org.springframework.context.annotation.Conditional; +import org.springframework.core.type.AnnotatedTypeMetadata; +import org.springframework.stereotype.Component; +import org.tron.common.client.DatabaseGrpcClient; +import org.tron.common.es.ExecutorServiceManager; +import org.tron.common.parameter.CommonParameter; +import org.tron.core.ChainBaseManager; +import org.tron.core.capsule.BlockCapsule; +import org.tron.core.config.args.Args; +import org.tron.core.exception.TronError; +import org.tron.core.net.TronNetDelegate; +import org.tron.protos.Protocol.Block; + +@Slf4j(topic = "app") +@Conditional(value = {SolidityNode.SolidityCondition.class}) +@Component +public class SolidityNode { + + @Autowired + private ChainBaseManager chainBaseManager; + + @Autowired + private TronNetDelegate tronNetDelegate; + + private DatabaseGrpcClient databaseGrpcClient; + + private final AtomicLong ID = new AtomicLong(); + + private final AtomicLong remoteBlockNum = new AtomicLong(); + + private final LinkedBlockingDeque blockQueue = new LinkedBlockingDeque<>(100); + + private final int exceptionSleepTime = 1000; + + private volatile boolean flag = true; + + private final String getBlockName = "get-block"; + private final String processBlockName = "process-block"; + + private ExecutorService getBlockExecutor; + private ExecutorService processBlockExecutor; + + @PostConstruct + private void init() { + resolveCompatibilityIssueIfUsingFullNodeDatabase(); + ID.set(chainBaseManager.getDynamicPropertiesStore().getLatestSolidifiedBlockNum()); + getBlockExecutor = ExecutorServiceManager.newSingleThreadExecutor(getBlockName); + processBlockExecutor = ExecutorServiceManager.newSingleThreadExecutor(processBlockName); + } + + @PreDestroy + private void shutdown() { + flag = false; + ExecutorServiceManager.shutdownAndAwaitTermination(getBlockExecutor, getBlockName); + ExecutorServiceManager.shutdownAndAwaitTermination(processBlockExecutor, processBlockName); + if (databaseGrpcClient != null) { + databaseGrpcClient.shutdown(); + } + } + + public void run() { + try { + databaseGrpcClient = new DatabaseGrpcClient(CommonParameter.getInstance().getTrustNodeAddr()); + remoteBlockNum.set(getLastSolidityBlockNum()); + + getBlockExecutor.submit(this::getBlock); + processBlockExecutor.submit(this::processSolidityBlock); + logger.info("Success to start solid node, ID: {}, remoteBlockNum: {}.", ID.get(), + remoteBlockNum); + } catch (Exception e) { + logger.error("Failed to start solid node, address: {}.", + CommonParameter.getInstance().getTrustNodeAddr()); + throw new TronError(e, TronError.ErrCode.SOLID_NODE_INIT); + } + } + + private void getBlock() { + long blockNum = ID.incrementAndGet(); + while (flag) { + try { + if (blockNum > remoteBlockNum.get()) { + sleep(BLOCK_PRODUCED_INTERVAL); + remoteBlockNum.set(getLastSolidityBlockNum()); + continue; + } + Block block = getBlockByNum(blockNum); + blockQueue.put(block); + blockNum = ID.incrementAndGet(); + } catch (Exception e) { + logger.error("Failed to get block {}, reason: {}.", blockNum, e.getMessage()); + sleep(exceptionSleepTime); + } + } + } + + private void processSolidityBlock() { + while (flag) { + try { + Block block = blockQueue.take(); + loopProcessBlock(block); + } catch (Exception e) { + logger.error(e.getMessage()); + sleep(exceptionSleepTime); + } + } + } + + private void loopProcessBlock(Block block) { + while (flag) { + long blockNum = block.getBlockHeader().getRawData().getNumber(); + try { + tronNetDelegate.pushVerifiedBlock(new BlockCapsule(block)); + chainBaseManager.getDynamicPropertiesStore().saveLatestSolidifiedBlockNum(blockNum); + logger + .info("Success to process block: {}, blockQueueSize: {}.", blockNum, blockQueue.size()); + return; + } catch (Exception e) { + logger.error("Failed to process block {}.", new BlockCapsule(block), e); + sleep(exceptionSleepTime); + block = getBlockByNum(blockNum); + } + } + } + + private Block getBlockByNum(long blockNum) { + while (flag) { + try { + long time = System.currentTimeMillis(); + Block block = databaseGrpcClient.getBlock(blockNum); + long num = block.getBlockHeader().getRawData().getNumber(); + if (num == blockNum) { + logger.info("Success to get block: {}, cost: {}ms.", + blockNum, System.currentTimeMillis() - time); + return block; + } else { + logger.warn("Get block id not the same , {}, {}.", num, blockNum); + sleep(exceptionSleepTime); + } + } catch (Exception e) { + logger.error("Failed to get block: {}, reason: {}.", blockNum, e.getMessage()); + sleep(exceptionSleepTime); + } + } + throw new RuntimeException("SolidityNode is closing."); + } + + private long getLastSolidityBlockNum() { + while (flag) { + try { + long time = System.currentTimeMillis(); + long blockNum = databaseGrpcClient.getDynamicProperties().getLastSolidityBlockNum(); + logger.info("Get last remote solid blockNum: {}, remoteBlockNum: {}, cost: {}.", + blockNum, remoteBlockNum, System.currentTimeMillis() - time); + return blockNum; + } catch (Exception e) { + logger.error("Failed to get last solid blockNum: {}, reason: {}.", remoteBlockNum.get(), + e.getMessage()); + sleep(exceptionSleepTime); + } + } + throw new RuntimeException("SolidityNode is closing."); + } + + public void sleep(long time) { + try { + Thread.sleep(time); + } catch (Exception e1) { + logger.error(e1.getMessage()); + } + } + + private void resolveCompatibilityIssueIfUsingFullNodeDatabase() { + long lastSolidityBlockNum = + chainBaseManager.getDynamicPropertiesStore().getLatestSolidifiedBlockNum(); + long headBlockNum = chainBaseManager.getHeadBlockNum(); + logger.info("headBlockNum:{}, solidityBlockNum:{}, diff:{}", + headBlockNum, lastSolidityBlockNum, headBlockNum - lastSolidityBlockNum); + if (lastSolidityBlockNum < headBlockNum) { + logger.info("use fullNode database, headBlockNum:{}, solidityBlockNum:{}, diff:{}", + headBlockNum, lastSolidityBlockNum, headBlockNum - lastSolidityBlockNum); + chainBaseManager.getDynamicPropertiesStore().saveLatestSolidifiedBlockNum(headBlockNum); + } + } + + static class SolidityCondition implements Condition { + @Override + public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { + return Args.getInstance().isSolidityNode(); + } + } } \ No newline at end of file From 1e9c558c547061b1a486b3564cd18bb93b72f714 Mon Sep 17 00:00:00 2001 From: jiangyuanshu <317787106@qq.com> Date: Sat, 25 Apr 2026 12:05:53 +0800 Subject: [PATCH 7/7] add InterruptedException for processSolidityBlock --- .../java/org/tron/program/SolidityNode.java | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/framework/src/main/java/org/tron/program/SolidityNode.java b/framework/src/main/java/org/tron/program/SolidityNode.java index 78144311f81..e13f94b8bfe 100644 --- a/framework/src/main/java/org/tron/program/SolidityNode.java +++ b/framework/src/main/java/org/tron/program/SolidityNode.java @@ -4,10 +4,12 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.LinkedBlockingDeque; +import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicLong; import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; import lombok.extern.slf4j.Slf4j; +import org.checkerframework.checker.nullness.qual.NonNull; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Condition; import org.springframework.context.annotation.ConditionContext; @@ -25,7 +27,7 @@ import org.tron.protos.Protocol.Block; @Slf4j(topic = "app") -@Conditional(value = {SolidityNode.SolidityCondition.class}) +@Conditional(SolidityNode.SolidityCondition.class) @Component public class SolidityNode { @@ -109,8 +111,15 @@ private void getBlock() { private void processSolidityBlock() { while (flag) { try { - Block block = blockQueue.take(); + Block block = blockQueue.poll(exceptionSleepTime, TimeUnit.MILLISECONDS); + if (block == null) { + continue; + } loopProcessBlock(block); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + logger.info("processSolidityBlock interrupted."); + return; } catch (Exception e) { logger.error(e.getMessage()); sleep(exceptionSleepTime); @@ -196,9 +205,11 @@ private void resolveCompatibilityIssueIfUsingFullNodeDatabase() { } static class SolidityCondition implements Condition { + @Override - public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { + public boolean matches(@NonNull ConditionContext context, + @NonNull AnnotatedTypeMetadata metadata) { return Args.getInstance().isSolidityNode(); } } -} \ No newline at end of file +}