Skip to content

Commit 456b4eb

Browse files
authored
fix(net): optimize disconnect reason for light node (#6375)
* fix the bug of handshake with lightnode
1 parent 2dcdb45 commit 456b4eb

File tree

7 files changed

+101
-72
lines changed

7 files changed

+101
-72
lines changed

framework/src/main/java/org/tron/core/net/service/handshake/HandshakeService.java

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import org.springframework.stereotype.Component;
77
import org.tron.common.utils.ByteArray;
88
import org.tron.core.ChainBaseManager;
9+
import org.tron.core.ChainBaseManager.NodeType;
910
import org.tron.core.config.args.Args;
1011
import org.tron.core.net.TronNetService;
1112
import org.tron.core.net.message.handshake.HelloMessage;
@@ -96,12 +97,17 @@ public void processHelloMessage(PeerConnection peer, HelloMessage msg) {
9697
}
9798

9899
if (chainBaseManager.getSolidBlockId().getNum() >= msg.getSolidBlockId().getNum()
99-
&& !chainBaseManager.containBlockInMainChain(msg.getSolidBlockId())) {
100-
logger.info("Peer {} different solid block, peer->{}, me->{}",
101-
peer.getInetSocketAddress(),
102-
msg.getSolidBlockId().getString(),
103-
chainBaseManager.getSolidBlockId().getString());
104-
peer.disconnect(ReasonCode.FORKED);
100+
&& !chainBaseManager.containBlockInMainChain(msg.getSolidBlockId())) {
101+
if (chainBaseManager.getLowestBlockNum() <= msg.getSolidBlockId().getNum()) {
102+
logger.info("Peer {} different solid block, fork with me, peer->{}, me->{}",
103+
peer.getInetSocketAddress(),
104+
msg.getSolidBlockId().getString(),
105+
chainBaseManager.getSolidBlockId().getString());
106+
peer.disconnect(ReasonCode.FORKED);
107+
} else {
108+
logger.info("Peer {} solid block is below than my lowest", peer.getInetSocketAddress());
109+
peer.disconnect(ReasonCode.LIGHT_NODE_SYNC_FAIL);
110+
}
105111
return;
106112
}
107113

framework/src/test/java/org/tron/core/jsonrpc/ApiUtilTest.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919

2020
public class ApiUtilTest {
2121

22-
2322
@BeforeClass
2423
public static void init() {
2524
Args.setParam(new String[]{}, "config-localtest.conf");

framework/src/test/java/org/tron/core/net/BaseNet.java

Lines changed: 0 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,10 @@
11
package org.tron.core.net;
22

3-
import io.netty.bootstrap.Bootstrap;
4-
import io.netty.channel.Channel;
5-
import io.netty.channel.ChannelInitializer;
6-
import io.netty.channel.ChannelOption;
7-
import io.netty.channel.DefaultMessageSizeEstimator;
8-
import io.netty.channel.FixedRecvByteBufAllocator;
9-
import io.netty.channel.nio.NioEventLoopGroup;
10-
import io.netty.channel.socket.nio.NioSocketChannel;
11-
import io.netty.handler.codec.ByteToMessageDecoder;
12-
import io.netty.handler.codec.protobuf.ProtobufVarint32FrameDecoder;
13-
import io.netty.handler.codec.protobuf.ProtobufVarint32LengthFieldPrepender;
14-
import io.netty.handler.timeout.ReadTimeoutHandler;
15-
import io.netty.handler.timeout.WriteTimeoutHandler;
16-
import java.io.File;
173
import java.io.IOException;
184
import java.util.Collection;
195
import java.util.Objects;
206
import java.util.concurrent.ExecutorService;
217
import java.util.concurrent.Executors;
22-
import java.util.concurrent.TimeUnit;
238
import lombok.extern.slf4j.Slf4j;
249
import org.junit.AfterClass;
2510
import org.junit.Assert;
@@ -30,7 +15,6 @@
3015
import org.tron.common.application.ApplicationFactory;
3116
import org.tron.common.application.TronApplicationContext;
3217
import org.tron.common.parameter.CommonParameter;
33-
import org.tron.common.utils.FileUtil;
3418
import org.tron.common.utils.PublicMethod;
3519
import org.tron.common.utils.ReflectUtils;
3620
import org.tron.core.Constant;
@@ -54,30 +38,6 @@ public class BaseNet {
5438

5539
private static ExecutorService executorService = Executors.newFixedThreadPool(1);
5640

57-
public static Channel connect(ByteToMessageDecoder decoder) throws InterruptedException {
58-
NioEventLoopGroup group = new NioEventLoopGroup(1);
59-
Bootstrap b = new Bootstrap();
60-
b.group(group).channel(NioSocketChannel.class)
61-
.handler(new ChannelInitializer<Channel>() {
62-
@Override
63-
protected void initChannel(Channel ch) throws Exception {
64-
ch.config().setRecvByteBufAllocator(new FixedRecvByteBufAllocator(256 * 1024));
65-
ch.config().setOption(ChannelOption.SO_RCVBUF, 256 * 1024);
66-
ch.config().setOption(ChannelOption.SO_BACKLOG, 1024);
67-
ch.pipeline()
68-
.addLast("readTimeoutHandler", new ReadTimeoutHandler(600, TimeUnit.SECONDS))
69-
.addLast("writeTimeoutHandler", new WriteTimeoutHandler(600, TimeUnit.SECONDS));
70-
ch.pipeline().addLast("protoPender", new ProtobufVarint32LengthFieldPrepender());
71-
ch.pipeline().addLast("lengthDecode", new ProtobufVarint32FrameDecoder());
72-
ch.pipeline().addLast("handshakeHandler", decoder);
73-
ch.closeFuture();
74-
}
75-
}).option(ChannelOption.SO_KEEPALIVE, true)
76-
.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 60000)
77-
.option(ChannelOption.MESSAGE_SIZE_ESTIMATOR, DefaultMessageSizeEstimator.DEFAULT);
78-
return b.connect(Constant.LOCAL_HOST, port).sync().channel();
79-
}
80-
8141
@BeforeClass
8242
public static void init() throws Exception {
8343
executorService.execute(() -> {

framework/src/test/java/org/tron/core/net/services/HandShakeServiceTest.java

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@ public void testOkHelloMessage()
101101
Node node = new Node(NetUtil.getNodeId(), a1.getAddress().getHostAddress(), null, a1.getPort());
102102
HelloMessage helloMessage = new HelloMessage(node, System.currentTimeMillis(),
103103
ChainBaseManager.getChainBaseManager());
104+
Assert.assertNotNull(helloMessage.toString());
104105

105106
Assert.assertEquals(Version.getVersion(),
106107
new String(helloMessage.getHelloMessage().getCodeVersion().toByteArray()));
@@ -228,7 +229,7 @@ public void testLowAndGenesisBlockNum() throws NoSuchMethodException {
228229

229230
Node node2 = new Node(NetUtil.getNodeId(), a1.getAddress().getHostAddress(), null, 10002);
230231

231-
//lowestBlockNum > headBlockNum
232+
//peer's lowestBlockNum > my headBlockNum => peer is light, LIGHT_NODE_SYNC_FAIL
232233
Protocol.HelloMessage.Builder builder =
233234
getHelloMessageBuilder(node2, System.currentTimeMillis(),
234235
ChainBaseManager.getChainBaseManager());
@@ -240,7 +241,7 @@ public void testLowAndGenesisBlockNum() throws NoSuchMethodException {
240241
Assert.fail();
241242
}
242243

243-
//genesisBlock is not equal
244+
//genesisBlock is not equal => INCOMPATIBLE_CHAIN
244245
builder = getHelloMessageBuilder(node2, System.currentTimeMillis(),
245246
ChainBaseManager.getChainBaseManager());
246247
BlockCapsule.BlockId gid = ChainBaseManager.getChainBaseManager().getGenesisBlockId();
@@ -256,9 +257,11 @@ public void testLowAndGenesisBlockNum() throws NoSuchMethodException {
256257
Assert.fail();
257258
}
258259

259-
//solidityBlock <= us, but not contained
260+
// peer's solidityBlock <= my solidityBlock, but not contained
261+
// and my lowestBlockNum <= peer's solidityBlock => FORKED
260262
builder = getHelloMessageBuilder(node2, System.currentTimeMillis(),
261263
ChainBaseManager.getChainBaseManager());
264+
262265
BlockCapsule.BlockId sid = ChainBaseManager.getChainBaseManager().getSolidBlockId();
263266

264267
Random gen = new Random();
@@ -276,6 +279,16 @@ public void testLowAndGenesisBlockNum() throws NoSuchMethodException {
276279
} catch (Exception e) {
277280
Assert.fail();
278281
}
282+
283+
// peer's solidityBlock <= my solidityBlock, but not contained
284+
// and my lowestBlockNum > peer's solidityBlock => i am light, LIGHT_NODE_SYNC_FAIL
285+
ChainBaseManager.getChainBaseManager().setLowestBlockNum(2);
286+
try {
287+
HelloMessage helloMessage = new HelloMessage(builder.build().toByteArray());
288+
method.invoke(p2pEventHandler, peer, helloMessage.getSendBytes());
289+
} catch (Exception e) {
290+
Assert.fail();
291+
}
279292
}
280293

281294
@Test

framework/src/test/java/org/tron/core/net/services/RelayServiceTest.java

Lines changed: 68 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
package org.tron.core.net.services;
22

3+
import static org.mockito.ArgumentMatchers.any;
4+
import static org.mockito.Mockito.doNothing;
35
import static org.mockito.Mockito.mock;
46

5-
import com.google.common.collect.Lists;
67
import com.google.protobuf.ByteString;
78
import java.lang.reflect.Field;
89
import java.lang.reflect.Method;
@@ -12,7 +13,6 @@
1213
import java.util.List;
1314
import java.util.Set;
1415
import javax.annotation.Resource;
15-
1616
import lombok.extern.slf4j.Slf4j;
1717
import org.bouncycastle.util.encoders.Hex;
1818
import org.junit.Assert;
@@ -21,19 +21,27 @@
2121
import org.mockito.Mockito;
2222
import org.springframework.context.ApplicationContext;
2323
import org.tron.common.BaseTest;
24+
import org.tron.common.crypto.SignInterface;
25+
import org.tron.common.crypto.SignUtils;
26+
import org.tron.common.parameter.CommonParameter;
27+
import org.tron.common.utils.ByteArray;
2428
import org.tron.common.utils.ReflectUtils;
29+
import org.tron.common.utils.Sha256Hash;
2530
import org.tron.core.ChainBaseManager;
2631
import org.tron.core.Constant;
2732
import org.tron.core.capsule.BlockCapsule;
2833
import org.tron.core.capsule.WitnessCapsule;
2934
import org.tron.core.config.args.Args;
3035
import org.tron.core.net.P2pEventHandlerImpl;
36+
import org.tron.core.net.TronNetDelegate;
37+
import org.tron.core.net.TronNetService;
3138
import org.tron.core.net.message.adv.BlockMessage;
3239
import org.tron.core.net.message.handshake.HelloMessage;
3340
import org.tron.core.net.peer.Item;
3441
import org.tron.core.net.peer.PeerConnection;
3542
import org.tron.core.net.peer.PeerManager;
3643
import org.tron.core.net.service.relay.RelayService;
44+
import org.tron.p2p.P2pConfig;
3745
import org.tron.p2p.connection.Channel;
3846
import org.tron.p2p.discover.Node;
3947
import org.tron.p2p.utils.NetUtil;
@@ -44,11 +52,13 @@ public class RelayServiceTest extends BaseTest {
4452

4553
@Resource
4654
private RelayService service;
47-
@Resource
48-
private PeerConnection peer;
55+
4956
@Resource
5057
private P2pEventHandlerImpl p2pEventHandler;
5158

59+
@Resource
60+
private TronNetService tronNetService;
61+
5262
/**
5363
* init context.
5464
*/
@@ -67,8 +77,12 @@ public void test() throws Exception {
6777
}
6878

6979
private void initWitness() {
70-
byte[] key = Hex.decode("A04711BF7AFBDF44557DEFBDF4C4E7AA6138C6331F");
80+
// key: 0154435f065a57fec6af1e12eaa2fa600030639448d7809f4c65bdcf8baed7e5
81+
// Hex: A08A8D690BF36806C36A7DAE3AF796643C1AA9CC01
82+
// Base58: 27bi7CD8d94AgXY3XFS9A9vx78Si5MqrECz
83+
byte[] key = Hex.decode("A08A8D690BF36806C36A7DAE3AF796643C1AA9CC01");//exist already
7184
WitnessCapsule witnessCapsule = chainBaseManager.getWitnessStore().get(key);
85+
System.out.println(witnessCapsule.getInstance());
7286
witnessCapsule.setVoteCount(1000);
7387
chainBaseManager.getWitnessStore().put(key, witnessCapsule);
7488
List<ByteString> list = new ArrayList<>();
@@ -83,7 +97,7 @@ public void testGetNextWitnesses() throws Exception {
8397
"getNextWitnesses", ByteString.class, Integer.class);
8498
method.setAccessible(true);
8599
Set<ByteString> s1 = (Set<ByteString>) method.invoke(
86-
service, getFromHexString("A04711BF7AFBDF44557DEFBDF4C4E7AA6138C6331F"), 3);
100+
service, getFromHexString("A08A8D690BF36806C36A7DAE3AF796643C1AA9CC01"), 3);
87101
Assert.assertEquals(3, s1.size());
88102
assertContains(s1, "A0299F3DB80A24B20A254B89CE639D59132F157F13");
89103
assertContains(s1, "A0807337F180B62A77576377C1D0C9C24DF5C0DD62");
@@ -93,35 +107,51 @@ public void testGetNextWitnesses() throws Exception {
93107
service, getFromHexString("A0FAB5FBF6AFB681E4E37E9D33BDDB7E923D6132E5"), 3);
94108
Assert.assertEquals(3, s2.size());
95109
assertContains(s2, "A014EEBE4D30A6ACB505C8B00B218BDC4733433C68");
96-
assertContains(s2, "A04711BF7AFBDF44557DEFBDF4C4E7AA6138C6331F");
110+
assertContains(s2, "A08A8D690BF36806C36A7DAE3AF796643C1AA9CC01");
97111
assertContains(s2, "A0299F3DB80A24B20A254B89CE639D59132F157F13");
98112

99113
Set<ByteString> s3 = (Set<ByteString>) method.invoke(
100-
service, getFromHexString("A04711BF7AFBDF44557DEFBDF4C4E7AA6138C6331F"), 1);
114+
service, getFromHexString("A08A8D690BF36806C36A7DAE3AF796643C1AA9CC01"), 1);
101115
Assert.assertEquals(1, s3.size());
102116
assertContains(s3, "A0299F3DB80A24B20A254B89CE639D59132F157F13");
103117
}
104118

105119
private void testBroadcast() {
106120
try {
121+
PeerConnection peer = new PeerConnection();
122+
InetSocketAddress a1 = new InetSocketAddress("127.0.0.2", 10001);
123+
Channel c1 = mock(Channel.class);
124+
Mockito.when(c1.getInetSocketAddress()).thenReturn(a1);
125+
Mockito.when(c1.getInetAddress()).thenReturn(a1.getAddress());
126+
doNothing().when(c1).send((byte[]) any());
127+
128+
peer.setChannel(c1);
107129
peer.setAddress(getFromHexString("A0299F3DB80A24B20A254B89CE639D59132F157F13"));
108130
peer.setNeedSyncFromPeer(false);
109131
peer.setNeedSyncFromUs(false);
110132

111-
List<PeerConnection> peers = Lists.newArrayList();
133+
List<PeerConnection> peers = new ArrayList<>();
112134
peers.add(peer);
113-
ReflectUtils.setFieldValue(p2pEventHandler, "activePeers", peers);
135+
136+
TronNetDelegate tronNetDelegate = Mockito.mock(TronNetDelegate.class);
137+
Mockito.doReturn(peers).when(tronNetDelegate).getActivePeer();
138+
139+
Field field = service.getClass().getDeclaredField("tronNetDelegate");
140+
field.setAccessible(true);
141+
field.set(service, tronNetDelegate);
142+
114143
BlockCapsule blockCapsule = new BlockCapsule(chainBaseManager.getHeadBlockNum() + 1,
115144
chainBaseManager.getHeadBlockId(),
116-
0, getFromHexString("A04711BF7AFBDF44557DEFBDF4C4E7AA6138C6331F"));
145+
0, getFromHexString("A08A8D690BF36806C36A7DAE3AF796643C1AA9CC01"));
117146
BlockMessage msg = new BlockMessage(blockCapsule);
118147
service.broadcast(msg);
119148
Item item = new Item(blockCapsule.getBlockId(), Protocol.Inventory.InventoryType.BLOCK);
120149
Assert.assertEquals(1, peer.getAdvInvSpread().size());
121150
Assert.assertNotNull(peer.getAdvInvSpread().getIfPresent(item));
122151
peer.getChannel().close();
123-
} catch (NullPointerException e) {
124-
System.out.println(e);
152+
} catch (Exception e) {
153+
logger.info("", e);
154+
assert false;
125155
}
126156
}
127157

@@ -135,20 +165,32 @@ private ByteString getFromHexString(String s) {
135165
}
136166

137167
private void testCheckHelloMessage() {
138-
ByteString address = getFromHexString("A04711BF7AFBDF44557DEFBDF4C4E7AA6138C6331F");
168+
String key = "0154435f065a57fec6af1e12eaa2fa600030639448d7809f4c65bdcf8baed7e5";
169+
ByteString address = getFromHexString("A08A8D690BF36806C36A7DAE3AF796643C1AA9CC01");
139170
InetSocketAddress a1 = new InetSocketAddress("127.0.0.1", 10001);
140171
Node node = new Node(NetUtil.getNodeId(), a1.getAddress().getHostAddress(),
141172
null, a1.getPort());
173+
174+
SignInterface cryptoEngine = SignUtils.fromPrivate(ByteArray.fromHexString(key),
175+
Args.getInstance().isECKeyCryptoEngine());
142176
HelloMessage helloMessage = new HelloMessage(node, System.currentTimeMillis(),
143177
ChainBaseManager.getChainBaseManager());
178+
ByteString sig = ByteString.copyFrom(cryptoEngine.Base64toBytes(cryptoEngine
179+
.signHash(Sha256Hash.of(CommonParameter.getInstance()
180+
.isECKeyCryptoEngine(), ByteArray.fromLong(helloMessage
181+
.getTimestamp())).getBytes())));
144182
helloMessage.setHelloMessage(helloMessage.getHelloMessage().toBuilder()
145-
.setAddress(address).build());
183+
.setAddress(address)
184+
.setSignature(sig)
185+
.build());
186+
146187
Channel c1 = mock(Channel.class);
147188
Mockito.when(c1.getInetSocketAddress()).thenReturn(a1);
148189
Mockito.when(c1.getInetAddress()).thenReturn(a1.getAddress());
149190
Channel c2 = mock(Channel.class);
150191
Mockito.when(c2.getInetSocketAddress()).thenReturn(a1);
151192
Mockito.when(c2.getInetAddress()).thenReturn(a1.getAddress());
193+
152194
Args.getInstance().fastForward = true;
153195
ApplicationContext ctx = (ApplicationContext) ReflectUtils.getFieldObject(p2pEventHandler,
154196
"ctx");
@@ -158,14 +200,23 @@ private void testCheckHelloMessage() {
158200
PeerConnection peer2 = PeerManager.add(ctx, c2);
159201
assert peer2 != null;
160202
peer2.setAddress(address);
203+
204+
ReflectUtils.setFieldValue(tronNetService, "p2pConfig", new P2pConfig());
205+
161206
try {
162207
Field field = service.getClass().getDeclaredField("witnessScheduleStore");
163208
field.setAccessible(true);
164209
field.set(service, chainBaseManager.getWitnessScheduleStore());
210+
211+
Field field2 = service.getClass().getDeclaredField("manager");
212+
field2.setAccessible(true);
213+
field2.set(service, dbManager);
214+
165215
boolean res = service.checkHelloMessage(helloMessage, c1);
166-
Assert.assertFalse(res);
216+
Assert.assertTrue(res);
167217
} catch (Exception e) {
168-
logger.info("{}", e.getMessage());
218+
logger.info("", e);
219+
assert false;
169220
}
170221
}
171222
}

0 commit comments

Comments
 (0)