From 0d48db4870390f2afdb19bd4ca51a9baf7e4a334 Mon Sep 17 00:00:00 2001 From: wubin01 Date: Thu, 28 Dec 2023 10:41:49 +0800 Subject: [PATCH] =?UTF-8?q?feat(net):=C2=A0stop=20broadcasting=20transacti?= =?UTF-8?q?ons=20when=20the=20block=20cannot=20be=20solidified?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/parameter/CommonParameter.java | 8 +++ .../src/main/java/org/tron/core/Constant.java | 4 ++ .../src/main/java/org/tron/core/Wallet.java | 7 +++ .../java/org/tron/core/config/args/Args.java | 10 ++++ .../org/tron/core/net/TronNetDelegate.java | 15 ++++++ .../messagehandler/InventoryMsgHandler.java | 7 +++ .../org/tron/core/config/args/ArgsTest.java | 2 + .../tron/core/net/TronNetDelegateTest.java | 51 +++++++++++++++++++ .../InventoryMsgHandlerTest.java | 22 +++++++- protocol/src/main/protos/api/api.proto | 2 + 10 files changed, 126 insertions(+), 2 deletions(-) create mode 100644 framework/src/test/java/org/tron/core/net/TronNetDelegateTest.java diff --git a/common/src/main/java/org/tron/common/parameter/CommonParameter.java b/common/src/main/java/org/tron/common/parameter/CommonParameter.java index f8f6e6c5edb..319dd025c90 100644 --- a/common/src/main/java/org/tron/common/parameter/CommonParameter.java +++ b/common/src/main/java/org/tron/common/parameter/CommonParameter.java @@ -651,6 +651,14 @@ public class CommonParameter { @Setter public long allowCancelAllUnfreezeV2; + @Getter + @Setter + public boolean unsolidifiedBlockCheck; + + @Getter + @Setter + public int maxUnsolidifiedBlocks; + private static double calcMaxTimeRatio() { //return max(2.0, min(5.0, 5 * 4.0 / max(Runtime.getRuntime().availableProcessors(), 1))); return 5.0; diff --git a/common/src/main/java/org/tron/core/Constant.java b/common/src/main/java/org/tron/core/Constant.java index ba867793b41..96e99b72079 100644 --- a/common/src/main/java/org/tron/core/Constant.java +++ b/common/src/main/java/org/tron/core/Constant.java @@ -371,4 +371,8 @@ public class Constant { public static final String DYNAMIC_CONFIG_CHECK_INTERVAL = "node.dynamicConfig.checkInterval"; public static final String COMMITTEE_ALLOW_TVM_SHANGHAI = "committee.allowTvmShangHai"; + + public static final String UNSOLIDIFIED_BLOCK_CHECK = "node.unsolidifiedBlockCheck"; + + public static final String MAX_UNSOLIDIFIED_BLOCKS = "node.maxUnsolidifiedBlocks"; } diff --git a/framework/src/main/java/org/tron/core/Wallet.java b/framework/src/main/java/org/tron/core/Wallet.java index 0865e202974..a36ea5855ec 100755 --- a/framework/src/main/java/org/tron/core/Wallet.java +++ b/framework/src/main/java/org/tron/core/Wallet.java @@ -520,6 +520,13 @@ public GrpcAPI.Return broadcastTransaction(Transaction signedTransaction) { } } + if (tronNetDelegate.unsolidifiedBlockCheck()) { + logger.warn("Broadcast transaction {} has failed, block unsolidified.", txID); + return builder.setResult(false).setCode(response_code.BLOCK_UNSOLIDIFIED) + .setMessage(ByteString.copyFromUtf8("Bock unsolidified.")) + .build(); + } + if (dbManager.isTooManyPending()) { logger.warn("Broadcast transaction {} has failed, too many pending.", txID); return builder.setResult(false).setCode(response_code.SERVER_BUSY) diff --git a/framework/src/main/java/org/tron/core/config/args/Args.java b/framework/src/main/java/org/tron/core/config/args/Args.java index 75140dd5f54..0ca6b004fa7 100644 --- a/framework/src/main/java/org/tron/core/config/args/Args.java +++ b/framework/src/main/java/org/tron/core/config/args/Args.java @@ -230,6 +230,8 @@ public static void clearParam() { PARAMETER.dynamicConfigEnable = false; PARAMETER.dynamicConfigCheckInterval = 600; PARAMETER.allowTvmShangHai = 0; + PARAMETER.unsolidifiedBlockCheck = true; + PARAMETER.maxUnsolidifiedBlocks = 1000; } /** @@ -1178,6 +1180,14 @@ public static void setParam(final String[] args, final String confFileName) { config.hasPath(Constant.COMMITTEE_ALLOW_TVM_SHANGHAI) ? config .getInt(Constant.COMMITTEE_ALLOW_TVM_SHANGHAI) : 0; + PARAMETER.unsolidifiedBlockCheck = + !config.hasPath(Constant.UNSOLIDIFIED_BLOCK_CHECK) + || config.getBoolean(Constant.UNSOLIDIFIED_BLOCK_CHECK); + + PARAMETER.maxUnsolidifiedBlocks = + config.hasPath(Constant.MAX_UNSOLIDIFIED_BLOCKS) ? config + .getInt(Constant.MAX_UNSOLIDIFIED_BLOCKS) : 1000; + logConfig(); } 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 5d09e67908d..3aa06362cc9 100644 --- a/framework/src/main/java/org/tron/core/net/TronNetDelegate.java +++ b/framework/src/main/java/org/tron/core/net/TronNetDelegate.java @@ -29,6 +29,7 @@ import org.tron.core.capsule.BlockCapsule.BlockId; import org.tron.core.capsule.PbftSignCapsule; import org.tron.core.capsule.TransactionCapsule; +import org.tron.core.config.args.Args; import org.tron.core.db.Manager; import org.tron.core.exception.AccountResourceInsufficientException; import org.tron.core.exception.BadBlockException; @@ -98,6 +99,11 @@ public class TronNetDelegate { @Setter private volatile boolean exit = true; + private int maxUnsolidifiedBlocks = Args.getInstance().getMaxUnsolidifiedBlocks(); + + private boolean unsolidifiedBlockCheck + = Args.getInstance().isUnsolidifiedBlockCheck(); + private Cache freshBlockId = CacheBuilder.newBuilder() .maximumSize(blockIdCacheSize).expireAfterWrite(1, TimeUnit.HOURS) .recordStats().build(); @@ -365,4 +371,13 @@ public long getMaintenanceTimeInterval() { return chainBaseManager.getDynamicPropertiesStore().getMaintenanceTimeInterval(); } + public boolean unsolidifiedBlockCheck() { + if (!unsolidifiedBlockCheck) { + return false; + } + long headNum = chainBaseManager.getHeadBlockNum(); + long solidNum = chainBaseManager.getSolidBlockId().getNum(); + return headNum - solidNum >= maxUnsolidifiedBlocks; + } + } diff --git a/framework/src/main/java/org/tron/core/net/messagehandler/InventoryMsgHandler.java b/framework/src/main/java/org/tron/core/net/messagehandler/InventoryMsgHandler.java index 02b04d73b32..40b0db33482 100644 --- a/framework/src/main/java/org/tron/core/net/messagehandler/InventoryMsgHandler.java +++ b/framework/src/main/java/org/tron/core/net/messagehandler/InventoryMsgHandler.java @@ -43,6 +43,7 @@ public void processMessage(PeerConnection peer, TronMessage msg) { } private boolean check(PeerConnection peer, InventoryMessage inventoryMessage) { + InventoryType type = inventoryMessage.getInventoryType(); int size = inventoryMessage.getHashList().size(); @@ -52,6 +53,12 @@ private boolean check(PeerConnection peer, InventoryMessage inventoryMessage) { return false; } + if (type.equals(InventoryType.TRX) && tronNetDelegate.unsolidifiedBlockCheck()) { + logger.warn("Drop inv: {} size: {} from Peer {}, block unsolidified", + type, size, peer.getInetAddress()); + return false; + } + if (type.equals(InventoryType.TRX) && transactionsMsgHandler.isBusy()) { logger.warn("Drop inv: {} size: {} from Peer {}, transactionsMsgHandler is busy", type, size, peer.getInetAddress()); diff --git a/framework/src/test/java/org/tron/core/config/args/ArgsTest.java b/framework/src/test/java/org/tron/core/config/args/ArgsTest.java index 13e272d1e13..78d3ea0c6e6 100644 --- a/framework/src/test/java/org/tron/core/config/args/ArgsTest.java +++ b/framework/src/test/java/org/tron/core/config/args/ArgsTest.java @@ -102,6 +102,8 @@ public void get() { Assert.assertEquals(0, parameter.getActiveNodes().size()); Assert.assertEquals(30, parameter.getMaxConnections()); Assert.assertEquals(43, parameter.getNodeP2pVersion()); + Assert.assertEquals(1000, parameter.getMaxUnsolidifiedBlocks()); + Assert.assertEquals(true, parameter.isUnsolidifiedBlockCheck()); //Assert.assertEquals(30, args.getSyncNodeCount()); // gRPC network configs checking diff --git a/framework/src/test/java/org/tron/core/net/TronNetDelegateTest.java b/framework/src/test/java/org/tron/core/net/TronNetDelegateTest.java new file mode 100644 index 00000000000..674c13a73fe --- /dev/null +++ b/framework/src/test/java/org/tron/core/net/TronNetDelegateTest.java @@ -0,0 +1,51 @@ +package org.tron.core.net; + +import static org.mockito.Mockito.mock; + +import java.lang.reflect.Field; +import org.junit.Assert; +import org.junit.Test; +import org.mockito.Mockito; +import org.tron.common.parameter.CommonParameter; +import org.tron.common.utils.Sha256Hash; +import org.tron.core.ChainBaseManager; +import org.tron.core.Constant; +import org.tron.core.capsule.BlockCapsule; +import org.tron.core.config.args.Args; + +public class TronNetDelegateTest { + + @Test + public void test() throws Exception { + Args.setParam(new String[] {"-w"}, Constant.TEST_CONF); + CommonParameter parameter = Args.getInstance(); + Args.logConfig(); + + BlockCapsule.BlockId blockId = new BlockCapsule.BlockId(Sha256Hash.ZERO_HASH, 10000L); + + TronNetDelegate tronNetDelegate = new TronNetDelegate(); + + ChainBaseManager chainBaseManager = mock(ChainBaseManager.class); + Mockito.when(chainBaseManager.getHeadBlockNum()).thenReturn(10000L); + Mockito.when(chainBaseManager.getSolidBlockId()).thenReturn(blockId); + + Field field = tronNetDelegate.getClass().getDeclaredField("chainBaseManager"); + field.setAccessible(true); + field.set(tronNetDelegate, chainBaseManager); + + Assert.assertTrue(!tronNetDelegate.unsolidifiedBlockCheck()); + + blockId = new BlockCapsule.BlockId(Sha256Hash.ZERO_HASH, 1L); + Mockito.when(chainBaseManager.getSolidBlockId()).thenReturn(blockId); + Assert.assertTrue(tronNetDelegate.unsolidifiedBlockCheck()); + + parameter.setUnsolidifiedBlockCheck(false); + tronNetDelegate = new TronNetDelegate(); + + field = tronNetDelegate.getClass().getDeclaredField("unsolidifiedBlockCheck"); + field.setAccessible(true); + field.set(tronNetDelegate, false); + + Assert.assertTrue(!tronNetDelegate.unsolidifiedBlockCheck()); + } +} diff --git a/framework/src/test/java/org/tron/core/net/messagehandler/InventoryMsgHandlerTest.java b/framework/src/test/java/org/tron/core/net/messagehandler/InventoryMsgHandlerTest.java index 97db6207b2a..ee16d333193 100644 --- a/framework/src/test/java/org/tron/core/net/messagehandler/InventoryMsgHandlerTest.java +++ b/framework/src/test/java/org/tron/core/net/messagehandler/InventoryMsgHandlerTest.java @@ -1,10 +1,16 @@ package org.tron.core.net.messagehandler; +import static org.mockito.Mockito.mock; + import java.lang.reflect.Field; import java.net.InetAddress; import java.net.InetSocketAddress; import java.util.ArrayList; import org.junit.Test; +import org.mockito.Mockito; +import org.tron.core.Constant; +import org.tron.core.config.args.Args; +import org.tron.core.net.TronNetDelegate; import org.tron.core.net.message.adv.InventoryMessage; import org.tron.core.net.peer.PeerConnection; import org.tron.p2p.connection.Channel; @@ -12,10 +18,12 @@ public class InventoryMsgHandlerTest { - private InventoryMsgHandler handler = new InventoryMsgHandler(); - @Test public void testProcessMessage() throws Exception { + InventoryMsgHandler handler = new InventoryMsgHandler(); + Args.setParam(new String[] {"-w"}, Constant.TEST_CONF); + Args.logConfig(); + InventoryMessage msg = new InventoryMessage(new ArrayList<>(), InventoryType.TRX); PeerConnection peer = new PeerConnection(); peer.setChannel(getChannel("1.0.0.3", 1000)); @@ -31,6 +39,16 @@ public void testProcessMessage() throws Exception { peer.setNeedSyncFromUs(true); handler.processMessage(peer, msg); + peer.setNeedSyncFromUs(false); + + TronNetDelegate tronNetDelegate = mock(TronNetDelegate.class); + Mockito.when(tronNetDelegate.unsolidifiedBlockCheck()).thenReturn(true); + + Field field = handler.getClass().getDeclaredField("tronNetDelegate"); + field.setAccessible(true); + field.set(handler, tronNetDelegate); + + handler.processMessage(peer, msg); } private Channel getChannel(String host, int port) throws Exception { diff --git a/protocol/src/main/protos/api/api.proto b/protocol/src/main/protos/api/api.proto index 9a7534cf6ce..2505fa48d6f 100644 --- a/protocol/src/main/protos/api/api.proto +++ b/protocol/src/main/protos/api/api.proto @@ -1051,6 +1051,8 @@ message Return { SERVER_BUSY = 9; NO_CONNECTION = 10; NOT_ENOUGH_EFFECTIVE_CONNECTION = 11; + BLOCK_UNSOLIDIFIED = 12; + OTHER_ERROR = 20; }