From 3e41f54863ed8794d46eb035580e51f074afffbe Mon Sep 17 00:00:00 2001 From: jiangyuanshu <317787106@qq.com> Date: Thu, 18 Dec 2025 16:31:41 +0800 Subject: [PATCH 1/7] add log Cache to decrese memory occupy of eth_newFilter --- .../core/services/jsonrpc/TronJsonRpc.java | 36 +++++++++++++++++++ .../services/jsonrpc/TronJsonRpcImpl.java | 28 +++++++++++---- 2 files changed, 58 insertions(+), 6 deletions(-) diff --git a/framework/src/main/java/org/tron/core/services/jsonrpc/TronJsonRpc.java b/framework/src/main/java/org/tron/core/services/jsonrpc/TronJsonRpc.java index 658c805103..fd1142b90b 100644 --- a/framework/src/main/java/org/tron/core/services/jsonrpc/TronJsonRpc.java +++ b/framework/src/main/java/org/tron/core/services/jsonrpc/TronJsonRpc.java @@ -7,6 +7,7 @@ import com.googlecode.jsonrpc4j.JsonRpcMethod; import java.io.IOException; import java.util.List; +import java.util.Objects; import java.util.concurrent.ExecutionException; import lombok.AllArgsConstructor; import lombok.Getter; @@ -23,6 +24,7 @@ import org.tron.core.exception.jsonrpc.JsonRpcInvalidRequestException; import org.tron.core.exception.jsonrpc.JsonRpcMethodNotFoundException; import org.tron.core.exception.jsonrpc.JsonRpcTooManyResultException; +import org.tron.core.net.peer.Item; import org.tron.core.services.jsonrpc.types.BlockResult; import org.tron.core.services.jsonrpc.types.BuildArguments; import org.tron.core.services.jsonrpc.types.CallArguments; @@ -472,5 +474,39 @@ public LogFilterElement(String blockHash, Long blockNum, String txId, Integer tx } this.removed = removed; } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || this.getClass() != o.getClass()) { + return false; + } + LogFilterElement item = (LogFilterElement) o; + if (!Objects.equals(blockHash, item.blockHash)) { + return false; + } + if (!Objects.equals(transactionHash, item.transactionHash)) { + return false; + } + if (!Objects.equals(transactionIndex, item.transactionIndex)) { + return false; + } + if (!Objects.equals(logIndex, item.logIndex)) { + return false; + } + return removed == item.removed; + } + + @Override + public int hashCode() { + int result = blockHash != null ? blockHash.hashCode() : 0; + result = 31 * result + (transactionHash != null ? transactionHash.hashCode() : 0); + result = 31 * result + (transactionIndex != null ? transactionIndex.hashCode() : 0); + result = 31 * result + (logIndex != null ? logIndex.hashCode() : 0); + return result + (removed ? 1 : 0); + } + } } diff --git a/framework/src/main/java/org/tron/core/services/jsonrpc/TronJsonRpcImpl.java b/framework/src/main/java/org/tron/core/services/jsonrpc/TronJsonRpcImpl.java index 7a1518038d..0ee2aff6f2 100644 --- a/framework/src/main/java/org/tron/core/services/jsonrpc/TronJsonRpcImpl.java +++ b/framework/src/main/java/org/tron/core/services/jsonrpc/TronJsonRpcImpl.java @@ -11,6 +11,8 @@ import static org.tron.core.services.jsonrpc.JsonRpcApiUtil.triggerCallContract; import com.alibaba.fastjson.JSON; +import com.google.common.cache.Cache; +import com.google.common.cache.CacheBuilder; import com.google.protobuf.ByteString; import com.google.protobuf.GeneratedMessageV3; import java.io.Closeable; @@ -25,10 +27,10 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; +import java.util.concurrent.TimeUnit; import java.util.regex.Pattern; import lombok.Getter; import lombok.extern.slf4j.Slf4j; -import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.StringUtils; import org.bouncycastle.util.encoders.Hex; import org.springframework.beans.factory.annotation.Autowired; @@ -110,6 +112,10 @@ public enum RequestSource { private static final String FILTER_NOT_FOUND = "filter not found"; public static final int EXPIRE_SECONDS = 5 * 60; + private static final Cache logElementCache = CacheBuilder.newBuilder() + .maximumSize(100_000L) + .expireAfterWrite(EXPIRE_SECONDS, TimeUnit.SECONDS) + .recordStats().build(); //LRU cache /** * for log filter in Full Json-RPC */ @@ -165,7 +171,7 @@ public enum RequestSource { @Autowired public TronJsonRpcImpl(@Autowired NodeInfoService nodeInfoService, @Autowired Wallet wallet, - @Autowired Manager manager) { + @Autowired Manager manager) { this.nodeInfoService = nodeInfoService; this.wallet = wallet; this.manager = manager; @@ -191,6 +197,9 @@ public static void handleBLockFilter(BlockFilterCapsule blockFilterCapsule) { } } + /** + * append LogsFilterCapsule's LogFilterElement list to each filter if matched + */ public static void handleLogsFilter(LogsFilterCapsule logsFilterCapsule) { Iterator> it; @@ -226,8 +235,15 @@ public static void handleLogsFilter(LogsFilterCapsule logsFilterCapsule) { LogMatch.matchBlock(logFilter, logsFilterCapsule.getBlockNumber(), logsFilterCapsule.getBlockHash(), logsFilterCapsule.getTxInfoList(), logsFilterCapsule.isRemoved()); - if (CollectionUtils.isNotEmpty(elements)) { - logFilterAndResult.getResult().addAll(elements); + + for (LogFilterElement element : elements) { + LogFilterElement newElement; + try { + newElement = logElementCache.get(element.hashCode(), () -> element); + } catch (ExecutionException e) { + continue; + } + logFilterAndResult.getResult().add(newElement); } } } @@ -797,7 +813,7 @@ public TransactionReceipt getTransactionReceipt(String txId) long blockNum = blockCapsule.getNum(); TransactionInfoList transactionInfoList = wallet.getTransactionInfoByBlockNum(blockNum); long energyFee = wallet.getEnergyFee(blockCapsule.getTimeStamp()); - + // Find transaction context TransactionReceipt.TransactionContext context = findTransactionContext(transactionInfoList, @@ -806,7 +822,7 @@ public TransactionReceipt getTransactionReceipt(String txId) if (context == null) { return null; // Transaction not found in block } - + return new TransactionReceipt(blockCapsule, transactionInfo, context, energyFee); } From f3f22b0348ae8ce459011536b71c2cd5940d0c20 Mon Sep 17 00:00:00 2001 From: jiangyuanshu <317787106@qq.com> Date: Thu, 18 Dec 2025 18:17:35 +0800 Subject: [PATCH 2/7] set the maximumSize to 300_000 --- .../java/org/tron/core/services/jsonrpc/TronJsonRpcImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/framework/src/main/java/org/tron/core/services/jsonrpc/TronJsonRpcImpl.java b/framework/src/main/java/org/tron/core/services/jsonrpc/TronJsonRpcImpl.java index 0ee2aff6f2..51ca7fd6c8 100644 --- a/framework/src/main/java/org/tron/core/services/jsonrpc/TronJsonRpcImpl.java +++ b/framework/src/main/java/org/tron/core/services/jsonrpc/TronJsonRpcImpl.java @@ -113,7 +113,7 @@ public enum RequestSource { private static final String FILTER_NOT_FOUND = "filter not found"; public static final int EXPIRE_SECONDS = 5 * 60; private static final Cache logElementCache = CacheBuilder.newBuilder() - .maximumSize(100_000L) + .maximumSize(300_000L) // 300s * tps(1000) * 1 log/tx ≈ 300_000 .expireAfterWrite(EXPIRE_SECONDS, TimeUnit.SECONDS) .recordStats().build(); //LRU cache /** From 8e801add5605a2029b0dcc25effeaa10b5ae914a Mon Sep 17 00:00:00 2001 From: jiangyuanshu <317787106@qq.com> Date: Thu, 18 Dec 2025 21:16:51 +0800 Subject: [PATCH 3/7] use same object as key and value --- .../core/services/jsonrpc/TronJsonRpcImpl.java | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/framework/src/main/java/org/tron/core/services/jsonrpc/TronJsonRpcImpl.java b/framework/src/main/java/org/tron/core/services/jsonrpc/TronJsonRpcImpl.java index 51ca7fd6c8..fd35f74c88 100644 --- a/framework/src/main/java/org/tron/core/services/jsonrpc/TronJsonRpcImpl.java +++ b/framework/src/main/java/org/tron/core/services/jsonrpc/TronJsonRpcImpl.java @@ -112,10 +112,11 @@ public enum RequestSource { private static final String FILTER_NOT_FOUND = "filter not found"; public static final int EXPIRE_SECONDS = 5 * 60; - private static final Cache logElementCache = CacheBuilder.newBuilder() - .maximumSize(300_000L) // 300s * tps(1000) * 1 log/tx ≈ 300_000 - .expireAfterWrite(EXPIRE_SECONDS, TimeUnit.SECONDS) - .recordStats().build(); //LRU cache + private static final Cache logElementCache = + CacheBuilder.newBuilder() + .maximumSize(300_000L) // 300s * tps(1000) * 1 log/tx ≈ 300_000 + .expireAfterWrite(EXPIRE_SECONDS, TimeUnit.SECONDS) + .recordStats().build(); //LRU cache /** * for log filter in Full Json-RPC */ @@ -171,7 +172,7 @@ public enum RequestSource { @Autowired public TronJsonRpcImpl(@Autowired NodeInfoService nodeInfoService, @Autowired Wallet wallet, - @Autowired Manager manager) { + @Autowired Manager manager) { this.nodeInfoService = nodeInfoService; this.wallet = wallet; this.manager = manager; @@ -239,8 +240,10 @@ public static void handleLogsFilter(LogsFilterCapsule logsFilterCapsule) { for (LogFilterElement element : elements) { LogFilterElement newElement; try { - newElement = logElementCache.get(element.hashCode(), () -> element); + //compare with hashcode() first, then with equals(). If not exist, put it. + newElement = logElementCache.get(element, () -> element); } catch (ExecutionException e) { + logger.error("Getting/loading LogFilterElement from cache fails", e);//never happen continue; } logFilterAndResult.getResult().add(newElement); From 4f78568cd0aa0ca8fe91f7a5849ffb70f9f97703 Mon Sep 17 00:00:00 2001 From: jiangyuanshu <317787106@qq.com> Date: Fri, 19 Dec 2025 11:20:34 +0800 Subject: [PATCH 4/7] invalidate cache when close --- .../java/org/tron/core/services/jsonrpc/TronJsonRpcImpl.java | 1 + 1 file changed, 1 insertion(+) diff --git a/framework/src/main/java/org/tron/core/services/jsonrpc/TronJsonRpcImpl.java b/framework/src/main/java/org/tron/core/services/jsonrpc/TronJsonRpcImpl.java index fd35f74c88..6b65f9d7ed 100644 --- a/framework/src/main/java/org/tron/core/services/jsonrpc/TronJsonRpcImpl.java +++ b/framework/src/main/java/org/tron/core/services/jsonrpc/TronJsonRpcImpl.java @@ -1548,6 +1548,7 @@ public static Object[] getFilterResult(String filterId, Map Date: Fri, 19 Dec 2025 14:20:12 +0800 Subject: [PATCH 5/7] use Objects.hash instead of concat hashcode --- .../org/tron/core/db2/core/SnapshotManager.java | 1 + .../tron/common/logsfilter/EventPluginLoader.java | 1 + .../org/tron/core/services/jsonrpc/TronJsonRpc.java | 7 +------ .../org/tron/core/jsonrpc/LogMatchExactlyTest.java | 13 +++++++++++++ 4 files changed, 16 insertions(+), 6 deletions(-) diff --git a/chainbase/src/main/java/org/tron/core/db2/core/SnapshotManager.java b/chainbase/src/main/java/org/tron/core/db2/core/SnapshotManager.java index 19f110c402..8c4e2dbf07 100644 --- a/chainbase/src/main/java/org/tron/core/db2/core/SnapshotManager.java +++ b/chainbase/src/main/java/org/tron/core/db2/core/SnapshotManager.java @@ -423,6 +423,7 @@ public List getCheckpointList() { private void deleteCheckpoint() { if(checkTmpStore == null) { + //only occurs in mock test. TODO fix test return; } try { diff --git a/framework/src/main/java/org/tron/common/logsfilter/EventPluginLoader.java b/framework/src/main/java/org/tron/common/logsfilter/EventPluginLoader.java index 6d16be5016..400d29709d 100644 --- a/framework/src/main/java/org/tron/common/logsfilter/EventPluginLoader.java +++ b/framework/src/main/java/org/tron/common/logsfilter/EventPluginLoader.java @@ -546,6 +546,7 @@ public boolean isBusy() { } int queueSize = 0; if (eventListeners == null || eventListeners.isEmpty()) { + //only occurs in mock test. TODO fix test return false; } for (IPluginEventListener listener : eventListeners) { diff --git a/framework/src/main/java/org/tron/core/services/jsonrpc/TronJsonRpc.java b/framework/src/main/java/org/tron/core/services/jsonrpc/TronJsonRpc.java index fd1142b90b..8f34d32a9a 100644 --- a/framework/src/main/java/org/tron/core/services/jsonrpc/TronJsonRpc.java +++ b/framework/src/main/java/org/tron/core/services/jsonrpc/TronJsonRpc.java @@ -24,7 +24,6 @@ import org.tron.core.exception.jsonrpc.JsonRpcInvalidRequestException; import org.tron.core.exception.jsonrpc.JsonRpcMethodNotFoundException; import org.tron.core.exception.jsonrpc.JsonRpcTooManyResultException; -import org.tron.core.net.peer.Item; import org.tron.core.services.jsonrpc.types.BlockResult; import org.tron.core.services.jsonrpc.types.BuildArguments; import org.tron.core.services.jsonrpc.types.CallArguments; @@ -501,11 +500,7 @@ public boolean equals(Object o) { @Override public int hashCode() { - int result = blockHash != null ? blockHash.hashCode() : 0; - result = 31 * result + (transactionHash != null ? transactionHash.hashCode() : 0); - result = 31 * result + (transactionIndex != null ? transactionIndex.hashCode() : 0); - result = 31 * result + (logIndex != null ? logIndex.hashCode() : 0); - return result + (removed ? 1 : 0); + return Objects.hash(blockHash, transactionHash, transactionIndex, logIndex, removed); } } diff --git a/framework/src/test/java/org/tron/core/jsonrpc/LogMatchExactlyTest.java b/framework/src/test/java/org/tron/core/jsonrpc/LogMatchExactlyTest.java index f55e3bc2cf..0f9f125b74 100644 --- a/framework/src/test/java/org/tron/core/jsonrpc/LogMatchExactlyTest.java +++ b/framework/src/test/java/org/tron/core/jsonrpc/LogMatchExactlyTest.java @@ -4,6 +4,7 @@ import java.util.ArrayList; import java.util.List; +import java.util.Objects; import org.junit.Assert; import org.junit.Test; import org.tron.common.runtime.vm.DataWord; @@ -220,6 +221,18 @@ public void testMatchBlock() { List elementList = matchBlock(logFilter, 100, null, transactionInfoList, false); Assert.assertEquals(1, elementList.size()); + + //test LogFilterElement + List elementList2 = + matchBlock(logFilter, 100, null, transactionInfoList, false); + Assert.assertEquals(1, elementList2.size()); + + LogFilterElement logFilterElement1 = elementList.get(0); + LogFilterElement logFilterElement2 = elementList2.get(0); + + Assert.assertEquals(logFilterElement1.hashCode(), logFilterElement2.hashCode()); + Assert.assertEquals(logFilterElement1, logFilterElement2); + } catch (JsonRpcInvalidParamsException e) { Assert.fail(); } From f0f0b0f84a3eada52b61fc37315367072fdd321d Mon Sep 17 00:00:00 2001 From: jiangyuanshu <317787106@qq.com> Date: Fri, 19 Dec 2025 15:53:27 +0800 Subject: [PATCH 6/7] add one testcase --- .../java/org/tron/common/logsfilter/EventPluginLoader.java | 2 +- .../main/java/org/tron/core/net/peer/PeerStatusCheck.java | 2 +- .../java/org/tron/core/services/jsonrpc/TronJsonRpcImpl.java | 4 ++-- .../test/java/org/tron/core/zksnark/ShieldedReceiveTest.java | 5 +++++ 4 files changed, 9 insertions(+), 4 deletions(-) diff --git a/framework/src/main/java/org/tron/common/logsfilter/EventPluginLoader.java b/framework/src/main/java/org/tron/common/logsfilter/EventPluginLoader.java index 400d29709d..7061b2e9d5 100644 --- a/framework/src/main/java/org/tron/common/logsfilter/EventPluginLoader.java +++ b/framework/src/main/java/org/tron/common/logsfilter/EventPluginLoader.java @@ -546,7 +546,7 @@ public boolean isBusy() { } int queueSize = 0; if (eventListeners == null || eventListeners.isEmpty()) { - //only occurs in mock test. TODO fix test + // only occurs in mock test. TODO fix test return false; } for (IPluginEventListener listener : eventListeners) { diff --git a/framework/src/main/java/org/tron/core/net/peer/PeerStatusCheck.java b/framework/src/main/java/org/tron/core/net/peer/PeerStatusCheck.java index 14bd2fe1ce..04eac20248 100644 --- a/framework/src/main/java/org/tron/core/net/peer/PeerStatusCheck.java +++ b/framework/src/main/java/org/tron/core/net/peer/PeerStatusCheck.java @@ -43,7 +43,7 @@ public void statusCheck() { long now = System.currentTimeMillis(); if (tronNetDelegate == null) { - //only occurs in mock test. TODO fix test + // only occurs in mock test. TODO fix test return; } tronNetDelegate.getActivePeer().forEach(peer -> { diff --git a/framework/src/main/java/org/tron/core/services/jsonrpc/TronJsonRpcImpl.java b/framework/src/main/java/org/tron/core/services/jsonrpc/TronJsonRpcImpl.java index 6b65f9d7ed..aa5ec4ad78 100644 --- a/framework/src/main/java/org/tron/core/services/jsonrpc/TronJsonRpcImpl.java +++ b/framework/src/main/java/org/tron/core/services/jsonrpc/TronJsonRpcImpl.java @@ -240,10 +240,10 @@ public static void handleLogsFilter(LogsFilterCapsule logsFilterCapsule) { for (LogFilterElement element : elements) { LogFilterElement newElement; try { - //compare with hashcode() first, then with equals(). If not exist, put it. + // compare with hashcode() first, then with equals(). If not exist, put it. newElement = logElementCache.get(element, () -> element); } catch (ExecutionException e) { - logger.error("Getting/loading LogFilterElement from cache fails", e);//never happen + logger.error("Getting/loading LogFilterElement from cache fails", e);// never happen continue; } logFilterAndResult.getResult().add(newElement); diff --git a/framework/src/test/java/org/tron/core/zksnark/ShieldedReceiveTest.java b/framework/src/test/java/org/tron/core/zksnark/ShieldedReceiveTest.java index 013d58b63c..bba23a230f 100755 --- a/framework/src/test/java/org/tron/core/zksnark/ShieldedReceiveTest.java +++ b/framework/src/test/java/org/tron/core/zksnark/ShieldedReceiveTest.java @@ -228,6 +228,11 @@ private void updateTotalShieldedPoolValue(long valueBalance) { chainBaseManager.getDynamicPropertiesStore().saveTotalShieldedPoolValue(totalShieldedPoolValue); } + @Test + public void testIsMining() { + Assert.assertTrue(wallet.isMining()); + } + /* * test of change ShieldedTransactionFee proposal */ From aabc0044fa2adf95515e15dd26eb2079e2687348 Mon Sep 17 00:00:00 2001 From: jiangyuanshu <317787106@qq.com> Date: Fri, 19 Dec 2025 15:55:33 +0800 Subject: [PATCH 7/7] format code --- .../src/main/java/org/tron/core/db2/core/SnapshotManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chainbase/src/main/java/org/tron/core/db2/core/SnapshotManager.java b/chainbase/src/main/java/org/tron/core/db2/core/SnapshotManager.java index 8c4e2dbf07..e20490d93c 100644 --- a/chainbase/src/main/java/org/tron/core/db2/core/SnapshotManager.java +++ b/chainbase/src/main/java/org/tron/core/db2/core/SnapshotManager.java @@ -423,7 +423,7 @@ public List getCheckpointList() { private void deleteCheckpoint() { if(checkTmpStore == null) { - //only occurs in mock test. TODO fix test + // only occurs in mock test. TODO fix test return; } try {