├── src ├── myConnection │ ├── MessageProcess.java │ ├── MyNodeDetectService.java │ ├── higher │ │ ├── MyHMessage │ │ │ ├── MyTronMessage.java │ │ │ ├── MyHFetchInvDataMessageMyH.java │ │ │ ├── MyHPbftCommitMessage.java │ │ │ ├── MyHPongMessage.java │ │ │ ├── MyHPingMessage.java │ │ │ ├── MyHSyncBlockChainMessage.java │ │ │ ├── MyHTransactionsMessage.java │ │ │ ├── MyHTransactionMessage.java │ │ │ ├── MyHDisconnectMessage.java │ │ │ ├── MyHBlockInventoryMessage.java │ │ │ ├── MyHBlockMessage.java │ │ │ ├── MyHInventoryMessage.java │ │ │ ├── MyHChainInventoryMessage.java │ │ │ └── MyHHelloMessage.java │ │ ├── H_keepalive │ │ │ └── MyHKeepAlive.java │ │ └── H_handshake │ │ │ └── MyHHandshake.java │ ├── MyP2pEventHandler.java │ ├── message │ │ ├── MyPongMessage.java │ │ ├── MyPingMessage.java │ │ ├── MyP2pDisconnectMessage.java │ │ ├── MyStatusMessage.java │ │ ├── MyHelloMessage.java │ │ └── MyMessage.java │ ├── socket │ │ ├── MyP2pChannelInitializer.java │ │ ├── MyPeerServer.java │ │ ├── MyP2pProtobufVariant32FrameDecoder.java │ │ ├── MyMessageHandler.java │ │ └── MyPeerClient.java │ ├── keepalive │ │ └── MyKeepAliveService.java │ ├── handshake │ │ └── MyHandshakeService.java │ ├── MyHP2pEventHandlerImpl.java │ ├── MyChannel.java │ └── MyChannelManager.java ├── myDiscover │ ├── NodeId.java │ ├── MyP2pService.java │ ├── UdpEvent.java │ ├── NodeIdTable.java │ ├── NodeIdBucket.java │ ├── MyEventHandler.java │ ├── MyKadPongMessage.java │ ├── MyKadPingMessage.java │ ├── MyP2pPacketDecoder.java │ ├── MyMessageHandler.java │ ├── Main.java │ ├── Tool.java │ └── MyConfig.java └── META-INF │ └── MANIFEST.MF ├── README.md └── tron_eclipse.iml /src/myConnection/MessageProcess.java: -------------------------------------------------------------------------------- 1 | package myConnection; 2 | 3 | import myConnection.message.MyMessage; 4 | 5 | public interface MessageProcess { 6 | void processMessage(MyChannel channel, MyMessage message); 7 | } 8 | -------------------------------------------------------------------------------- /src/myDiscover/NodeId.java: -------------------------------------------------------------------------------- 1 | package myDiscover; 2 | 3 | public class NodeId { 4 | private Byte[] nodeId; 5 | 6 | public NodeId(Byte[] nodeId) { 7 | this.nodeId = nodeId; 8 | } 9 | 10 | public Byte[] getNodeId() { 11 | return nodeId; 12 | } 13 | 14 | public void setNodeId(Byte[] nodeId) { 15 | this.nodeId = nodeId; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/myConnection/MyNodeDetectService.java: -------------------------------------------------------------------------------- 1 | package myConnection; 2 | 3 | import org.tron.p2p.connection.Channel; 4 | import org.tron.p2p.connection.message.Message; 5 | 6 | public class MyNodeDetectService { 7 | private final String testNum="test"; 8 | public void processMessage(Channel channel, Message message){ 9 | //do nothing for now 10 | System.out.printf(testNum); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/myConnection/higher/MyHMessage/MyTronMessage.java: -------------------------------------------------------------------------------- 1 | package myConnection.higher.MyHMessage; 2 | 3 | public abstract class MyTronMessage extends org.tron.common.overlay.message.Message{ 4 | public MyTronMessage() { 5 | } 6 | 7 | public MyTronMessage(byte[] rawData) { 8 | super(rawData); 9 | } 10 | 11 | public MyTronMessage(byte type, byte[] rawData) { 12 | super(type, rawData); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/myConnection/MyP2pEventHandler.java: -------------------------------------------------------------------------------- 1 | package myConnection; 2 | 3 | import lombok.Getter; 4 | 5 | import java.util.Set; 6 | 7 | public abstract class MyP2pEventHandler { 8 | @Getter 9 | protected Set messageTypes; 10 | 11 | public void onConnect(MyChannel channel) { 12 | } 13 | 14 | public void onDisconnect(MyChannel channel) { 15 | } 16 | 17 | public void onMessage(MyChannel channel, byte[] data) { 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/myDiscover/MyP2pService.java: -------------------------------------------------------------------------------- 1 | package myDiscover; 2 | 3 | import org.tron.p2p.P2pService; 4 | import org.tron.p2p.connection.ChannelManager; 5 | import org.tron.p2p.connection.business.pool.ConnPoolService; 6 | 7 | public class MyP2pService extends P2pService { 8 | public void killConnPoolService(){ 9 | ConnPoolService poolService=ChannelManager.getConnPoolService(); 10 | poolService.close(); 11 | System.out.println("ConnPoolService shutdown"); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/myDiscover/UdpEvent.java: -------------------------------------------------------------------------------- 1 | package myDiscover; 2 | 3 | import org.tron.p2p.discover.message.Message; 4 | 5 | import java.net.InetSocketAddress; 6 | public class UdpEvent { 7 | private final Message message; 8 | private final InetSocketAddress address; 9 | 10 | public UdpEvent(Message message, InetSocketAddress address) { 11 | this.message = message; 12 | this.address = address; 13 | } 14 | 15 | public Message getMessage() { 16 | return message; 17 | } 18 | 19 | public InetSocketAddress getAddress() { 20 | return address; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/myConnection/higher/H_keepalive/MyHKeepAlive.java: -------------------------------------------------------------------------------- 1 | package myConnection.higher.H_keepalive; 2 | 3 | import myConnection.MyChannel; 4 | import myConnection.higher.MyHMessage.MyHPongMessage; 5 | import myConnection.higher.MyHMessage.MyTronMessage; 6 | import org.tron.core.net.message.MessageTypes; 7 | 8 | public class MyHKeepAlive { 9 | public static void processMessage(MyChannel channel, MyTronMessage message){ 10 | if (message.getType().equals(MessageTypes.P2P_PING)) { 11 | MyHPongMessage msg = new MyHPongMessage(); 12 | channel.send(msg.getSendBytes()); 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/myDiscover/NodeIdTable.java: -------------------------------------------------------------------------------- 1 | package myDiscover; 2 | 3 | import java.util.Random; 4 | 5 | public class NodeIdTable { 6 | private NodeIdBucket[] nodeIdTable = new NodeIdBucket[17]; 7 | 8 | public NodeIdBucket[] getNodeIdTable() { 9 | return nodeIdTable; 10 | } 11 | 12 | public void init(NodeId nodeId){ 13 | boolean[] bitNodeId = Tool.byteArrayToBitArray(nodeId.getNodeId()); 14 | Random random = new Random(); 15 | for (int i =0; i<17;i++){ 16 | NodeIdBucket nodeIdBucket = new NodeIdBucket(); 17 | nodeIdBucket.init(nodeId,i); 18 | this.nodeIdTable[i]=nodeIdBucket; 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/META-INF/MANIFEST.MF: -------------------------------------------------------------------------------- 1 | Manifest-Version: 1.0 2 | Main-Class: myConnection.MyChannelManager 3 | Class-Path: netty-common-4.1.79.Final.jar guava-31.1-android.jar json-20 4 | 231013.jar spring-core-5.3.18.jar lombok-1.18.24.jar snappy-java-1.1.10 5 | .5.jar netty-buffer-4.1.79.Final.jar bcprov-jdk15on-1.69.jar protocol-1 6 | .0.0.jar logback-classic-1.2.9.jar netty-codec-4.1.79.Final.jar protoco 7 | l-core-2.18.41.jar logback-core-1.2.9.jar chainbase-1.0.0.jar commons-l 8 | ang3-3.16.0.jar libp2p-2.2.1.jar netty-transport-4.1.79.Final.jar proto 9 | buf-java-3.21.12.jar protobuf-java-util-3.21.12.jar netty-handler-4.1.7 10 | 9.Final.jar slf4j-api-1.7.36.jar common-1.0.0.jar netty-resolver-4.1.79 11 | .Final.jar 12 | 13 | -------------------------------------------------------------------------------- /src/myConnection/higher/MyHMessage/MyHFetchInvDataMessageMyH.java: -------------------------------------------------------------------------------- 1 | package myConnection.higher.MyHMessage; 2 | 3 | import org.tron.common.utils.Sha256Hash; 4 | import org.tron.core.net.message.MessageTypes; 5 | import org.tron.protos.Protocol.Inventory; 6 | import org.tron.protos.Protocol.Inventory.InventoryType; 7 | 8 | import java.util.List; 9 | 10 | public class MyHFetchInvDataMessageMyH extends MyHInventoryMessage { 11 | 12 | 13 | public MyHFetchInvDataMessageMyH(byte[] packed) throws Exception { 14 | super(packed); 15 | this.type = MessageTypes.FETCH_INV_DATA.asByte(); 16 | } 17 | 18 | public MyHFetchInvDataMessageMyH(Inventory inv) { 19 | super(inv); 20 | this.type = MessageTypes.FETCH_INV_DATA.asByte(); 21 | } 22 | 23 | public MyHFetchInvDataMessageMyH(List hashList, InventoryType type) { 24 | super(hashList, type); 25 | this.type = MessageTypes.FETCH_INV_DATA.asByte(); 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /src/myConnection/message/MyPongMessage.java: -------------------------------------------------------------------------------- 1 | package myConnection.message; 2 | 3 | import org.tron.p2p.connection.message.MessageType; 4 | import org.tron.p2p.protos.Connect; 5 | 6 | public class MyPongMessage extends MyMessage { 7 | 8 | private Connect.KeepAliveMessage keepAliveMessage; 9 | 10 | public MyPongMessage(byte[] data) throws Exception { 11 | super(MessageType.KEEP_ALIVE_PONG, data); 12 | this.keepAliveMessage = Connect.KeepAliveMessage.parseFrom(data); 13 | } 14 | 15 | public MyPongMessage() { 16 | super(MessageType.KEEP_ALIVE_PONG, null); 17 | this.keepAliveMessage = Connect.KeepAliveMessage.newBuilder() 18 | .setTimestamp(System.currentTimeMillis()).build(); 19 | this.data = this.keepAliveMessage.toByteArray(); 20 | } 21 | 22 | public long getTimeStamp() { 23 | return this.keepAliveMessage.getTimestamp(); 24 | } 25 | 26 | @Override 27 | public boolean valid() { 28 | return getTimeStamp() > 0; 29 | //&& getTimeStamp() <= System.currentTimeMillis() + MyConfig.NETWORK_TIME_DIFF; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/myDiscover/NodeIdBucket.java: -------------------------------------------------------------------------------- 1 | package myDiscover; 2 | 3 | import java.util.Random; 4 | 5 | public class NodeIdBucket { 6 | private NodeId[] nodeIdBucket = new NodeId[16]; 7 | 8 | public void init(NodeId nodeId, int distance) { 9 | boolean[] bitNodeId = Tool.byteArrayToBitArray(nodeId.getNodeId()); 10 | Random random = new Random(); 11 | for (int j = 0; j < 16; j++){ 12 | boolean[] tmpBitNodeId = new boolean[512]; 13 | Tool.copyFirstIBits(bitNodeId,tmpBitNodeId,distance); 14 | tmpBitNodeId[distance+1]=!bitNodeId[distance+1]; 15 | for (int k=distance+2;k<512;k++){ 16 | tmpBitNodeId[k]=random.nextBoolean(); 17 | } 18 | Byte[] tmpNodeId = Tool.bitArrayToByteArray(tmpBitNodeId); 19 | NodeId newNodeId = new NodeId(tmpNodeId); 20 | //newNodeId.setNodeId(tmpNodeId); 21 | this.nodeIdBucket[j]=newNodeId; 22 | } 23 | } 24 | 25 | public NodeId[] getNodeBucket() { 26 | return nodeIdBucket; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/myConnection/higher/MyHMessage/MyHPbftCommitMessage.java: -------------------------------------------------------------------------------- 1 | package myConnection.higher.MyHMessage; 2 | 3 | import org.tron.core.capsule.PbftSignCapsule; 4 | import org.tron.core.net.message.MessageTypes; 5 | import org.tron.protos.Protocol.PBFTCommitResult; 6 | 7 | public class MyHPbftCommitMessage extends MyTronMessage { 8 | 9 | private PbftSignCapsule pbftSignCapsule; 10 | 11 | public MyHPbftCommitMessage(byte[] data) { 12 | super(data); 13 | this.type = MessageTypes.PBFT_COMMIT_MSG.asByte(); 14 | this.pbftSignCapsule = new PbftSignCapsule(data); 15 | } 16 | 17 | public MyHPbftCommitMessage(PbftSignCapsule pbftSignCapsule) { 18 | data = pbftSignCapsule.getData(); 19 | this.type = MessageTypes.PBFT_COMMIT_MSG.asByte(); 20 | this.pbftSignCapsule = pbftSignCapsule; 21 | } 22 | 23 | public PBFTCommitResult getPBFTCommitResult() { 24 | return getPbftSignCapsule().getPbftCommitResult(); 25 | } 26 | 27 | public PbftSignCapsule getPbftSignCapsule() { 28 | return pbftSignCapsule; 29 | } 30 | 31 | @Override 32 | public Class getAnswerMessage() { 33 | return null; 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /src/myConnection/higher/MyHMessage/MyHPongMessage.java: -------------------------------------------------------------------------------- 1 | package myConnection.higher.MyHMessage; 2 | 3 | import org.bouncycastle.util.encoders.Hex; 4 | import org.tron.core.net.message.MessageTypes; 5 | 6 | public class MyHPongMessage extends MyTronMessage{ 7 | private static final byte[] FIXED_PAYLOAD = Hex.decode("C0"); 8 | 9 | public MyHPongMessage() { 10 | this.type = MessageTypes.P2P_PONG.asByte(); 11 | this.data = FIXED_PAYLOAD; 12 | } 13 | 14 | public MyHPongMessage(byte type, byte[] rawData) { 15 | super(type, rawData); 16 | } 17 | 18 | public MyHPongMessage(byte[] data) { 19 | super(MessageTypes.P2P_PONG.asByte(), data); 20 | } 21 | 22 | @Override 23 | public byte[] getData() { 24 | return FIXED_PAYLOAD; 25 | } 26 | 27 | @Override 28 | public String toString() { 29 | return super.toString(); 30 | } 31 | 32 | @Override 33 | public Class getAnswerMessage() { 34 | return null; 35 | } 36 | 37 | @Override 38 | public MessageTypes getType() { 39 | return MessageTypes.fromByte(this.type); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/myConnection/higher/MyHMessage/MyHPingMessage.java: -------------------------------------------------------------------------------- 1 | package myConnection.higher.MyHMessage; 2 | 3 | import org.bouncycastle.util.encoders.Hex; 4 | import org.tron.core.net.message.MessageTypes; 5 | 6 | public class MyHPingMessage extends MyTronMessage{ 7 | private static final byte[] FIXED_PAYLOAD = Hex.decode("C0"); 8 | 9 | public MyHPingMessage() { 10 | this.type = MessageTypes.P2P_PING.asByte(); 11 | this.data = FIXED_PAYLOAD; 12 | } 13 | 14 | public MyHPingMessage(byte type, byte[] rawData) { 15 | super(type, rawData); 16 | } 17 | 18 | public MyHPingMessage(byte[] data) { 19 | super(MessageTypes.P2P_PING.asByte(), data); 20 | } 21 | 22 | @Override 23 | public byte[] getData() { 24 | return FIXED_PAYLOAD; 25 | } 26 | 27 | 28 | @Override 29 | public String toString() { 30 | return super.toString(); 31 | } 32 | 33 | @Override 34 | public Class getAnswerMessage() { 35 | return MyHPongMessage.class; 36 | } 37 | 38 | @Override 39 | public MessageTypes getType() { 40 | return MessageTypes.fromByte(this.type); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/myConnection/message/MyPingMessage.java: -------------------------------------------------------------------------------- 1 | package myConnection.message; 2 | 3 | import myDiscover.MyConfig; 4 | import org.tron.p2p.connection.message.MessageType; 5 | import org.tron.p2p.protos.Connect; 6 | 7 | public class MyPingMessage extends MyMessage { 8 | 9 | private Connect.KeepAliveMessage keepAliveMessage; 10 | 11 | public MyPingMessage(byte[] data) throws Exception { 12 | super(MessageType.KEEP_ALIVE_PING, data); 13 | this.keepAliveMessage = Connect.KeepAliveMessage.parseFrom(data); 14 | } 15 | 16 | public MyPingMessage() { 17 | super(MessageType.KEEP_ALIVE_PING, null); 18 | this.keepAliveMessage = Connect.KeepAliveMessage.newBuilder() 19 | .setTimestamp(System.currentTimeMillis()).build(); 20 | this.data = this.keepAliveMessage.toByteArray(); 21 | } 22 | 23 | public long getTimeStamp() { 24 | return this.keepAliveMessage.getTimestamp(); 25 | } 26 | 27 | @Override 28 | public boolean valid() { 29 | System.out.println("System.currentTimeMillis() + MyConfig.NETWORK_TIME_DIFF = "+System.currentTimeMillis() + MyConfig.NETWORK_TIME_DIFF); 30 | System.out.println("TimeStamp = "+getTimeStamp()); 31 | return getTimeStamp() > 0; 32 | //&& getTimeStamp() <= System.currentTimeMillis() + MyConfig.NETWORK_TIME_DIFF; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/myConnection/message/MyP2pDisconnectMessage.java: -------------------------------------------------------------------------------- 1 | package myConnection.message; 2 | 3 | import org.tron.p2p.connection.message.MessageType; 4 | import org.tron.p2p.protos.Connect; 5 | 6 | public class MyP2pDisconnectMessage extends MyMessage { 7 | private Connect.P2pDisconnectMessage p2pDisconnectMessage; 8 | 9 | public MyP2pDisconnectMessage(byte[] data) throws Exception { 10 | super(MessageType.DISCONNECT, data); 11 | this.p2pDisconnectMessage = Connect.P2pDisconnectMessage.parseFrom(data); 12 | } 13 | 14 | public MyP2pDisconnectMessage(Connect.DisconnectReason disconnectReason) { 15 | super(MessageType.DISCONNECT, null); 16 | this.p2pDisconnectMessage = Connect.P2pDisconnectMessage.newBuilder() 17 | .setReason(disconnectReason).build(); 18 | this.data = p2pDisconnectMessage.toByteArray(); 19 | } 20 | 21 | private Connect.DisconnectReason getReason() { 22 | return p2pDisconnectMessage.getReason(); 23 | } 24 | 25 | @Override 26 | public boolean valid() { 27 | return true; 28 | } 29 | 30 | @Override 31 | public String toString() { 32 | return new StringBuilder().append(super.toString()).append("reason: ") 33 | .append(getReason()).toString(); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/myConnection/higher/MyHMessage/MyHSyncBlockChainMessage.java: -------------------------------------------------------------------------------- 1 | package myConnection.higher.MyHMessage; 2 | 3 | import org.tron.core.capsule.BlockCapsule.BlockId; 4 | import org.tron.core.net.message.MessageTypes; 5 | import org.tron.protos.Protocol.BlockInventory.Type; 6 | 7 | import java.util.List; 8 | 9 | public class MyHSyncBlockChainMessage extends MyHBlockInventoryMessage { 10 | 11 | public MyHSyncBlockChainMessage(byte[] packed) throws Exception { 12 | super(packed); 13 | this.type = MessageTypes.SYNC_BLOCK_CHAIN.asByte(); 14 | } 15 | 16 | public MyHSyncBlockChainMessage(List blockIds) { 17 | super(blockIds, Type.SYNC); 18 | this.type = MessageTypes.SYNC_BLOCK_CHAIN.asByte(); 19 | } 20 | 21 | @Override 22 | public String toString() { 23 | List blockIdList = getBlockIds(); 24 | StringBuilder sb = new StringBuilder(); 25 | int size = blockIdList.size(); 26 | sb.append(super.toString()).append("size: ").append(size); 27 | if (size >= 1) { 28 | sb.append(", start block: " + blockIdList.get(0).getString()); 29 | if (size > 1) { 30 | sb.append(", end block " + blockIdList.get(blockIdList.size() - 1).getString()); 31 | } 32 | } 33 | return sb.toString(); 34 | } 35 | 36 | @Override 37 | public Class getAnswerMessage() { 38 | return MyHChainInventoryMessage.class; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/myDiscover/MyEventHandler.java: -------------------------------------------------------------------------------- 1 | package myDiscover; 2 | 3 | import org.tron.p2p.discover.message.Message; 4 | import org.tron.p2p.discover.message.MessageType; 5 | 6 | public class MyEventHandler { 7 | public MyEventHandler(MyMessageHandler messageHandler) { 8 | this.messageHandler = messageHandler; 9 | } 10 | 11 | private MyMessageHandler messageHandler; 12 | 13 | public void handleEvent(UdpEvent udpEvent) { 14 | // 处理接收到的事件 15 | System.out.println("Handling event: " + udpEvent.getMessage().getType().toString()); 16 | Message msg = udpEvent.getMessage(); 17 | if (msg.getType()== MessageType.KAD_PING){ 18 | System.out.println("received msg type kad_ping"+System.currentTimeMillis()); 19 | Message pongReply=new MyKadPongMessage(); 20 | UdpEvent replyEvent = new UdpEvent(pongReply,udpEvent.getAddress()); 21 | messageHandler.accept(replyEvent); 22 | } 23 | else if (msg.getType()==MessageType.KAD_PONG) { 24 | System.out.println("received msg type kad_pong"); 25 | } 26 | 27 | } 28 | public void setMessageHandler(MyMessageHandler myMessageHandler){ 29 | this.messageHandler=myMessageHandler; 30 | } 31 | 32 | public void channelActivated() { 33 | System.out.println("Channel activated"); 34 | } 35 | } -------------------------------------------------------------------------------- /src/myConnection/higher/MyHMessage/MyHTransactionsMessage.java: -------------------------------------------------------------------------------- 1 | package myConnection.higher.MyHMessage; 2 | 3 | import org.tron.core.capsule.TransactionCapsule; 4 | import org.tron.core.net.message.MessageTypes; 5 | import org.tron.protos.Protocol; 6 | import org.tron.protos.Protocol.Transaction; 7 | 8 | import java.util.List; 9 | 10 | public class MyHTransactionsMessage extends MyTronMessage { 11 | 12 | private Protocol.Transactions transactions; 13 | 14 | public MyHTransactionsMessage(List trxs) { 15 | Protocol.Transactions.Builder builder = Protocol.Transactions.newBuilder(); 16 | trxs.forEach(trx -> builder.addTransactions(trx)); 17 | this.transactions = builder.build(); 18 | this.type = MessageTypes.TRXS.asByte(); 19 | this.data = this.transactions.toByteArray(); 20 | } 21 | 22 | public MyHTransactionsMessage(byte[] data) throws Exception { 23 | super(data); 24 | this.type = MessageTypes.TRXS.asByte(); 25 | this.transactions = Protocol.Transactions.parseFrom(getCodedInputStream(data)); 26 | if (isFilter()) { 27 | compareBytes(data, transactions.toByteArray()); 28 | TransactionCapsule.validContractProto(transactions.getTransactionsList()); 29 | } 30 | } 31 | 32 | public Protocol.Transactions getTransactions() { 33 | return transactions; 34 | } 35 | 36 | @Override 37 | public String toString() { 38 | return new StringBuilder().append(super.toString()).append("trx size: ") 39 | .append(this.transactions.getTransactionsList().size()).toString(); 40 | } 41 | 42 | @Override 43 | public Class getAnswerMessage() { 44 | return null; 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /src/myConnection/higher/MyHMessage/MyHTransactionMessage.java: -------------------------------------------------------------------------------- 1 | package myConnection.higher.MyHMessage; 2 | 3 | import org.tron.common.overlay.message.Message; 4 | import org.tron.common.utils.Sha256Hash; 5 | import org.tron.core.capsule.TransactionCapsule; 6 | import org.tron.core.net.message.MessageTypes; 7 | import org.tron.protos.Protocol.Transaction; 8 | 9 | public class MyHTransactionMessage extends MyTronMessage { 10 | 11 | private TransactionCapsule transactionCapsule; 12 | 13 | public MyHTransactionMessage(byte[] data) throws Exception { 14 | super(data); 15 | this.transactionCapsule = new TransactionCapsule(getCodedInputStream(data)); 16 | this.type = MessageTypes.TRX.asByte(); 17 | if (Message.isFilter()) { 18 | compareBytes(data, transactionCapsule.getInstance().toByteArray()); 19 | transactionCapsule 20 | .validContractProto(transactionCapsule.getInstance().getRawData().getContract(0)); 21 | } 22 | } 23 | 24 | public MyHTransactionMessage(Transaction trx) { 25 | this.transactionCapsule = new TransactionCapsule(trx); 26 | this.type = MessageTypes.TRX.asByte(); 27 | this.data = trx.toByteArray(); 28 | } 29 | 30 | @Override 31 | public String toString() { 32 | return new StringBuilder().append(super.toString()) 33 | .append("messageId: ").append(super.getMessageId()).toString(); 34 | } 35 | 36 | @Override 37 | public Sha256Hash getMessageId() { 38 | return this.transactionCapsule.getTransactionId(); 39 | } 40 | 41 | @Override 42 | public Class getAnswerMessage() { 43 | return null; 44 | } 45 | 46 | public TransactionCapsule getTransactionCapsule() { 47 | return this.transactionCapsule; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/myConnection/higher/MyHMessage/MyHDisconnectMessage.java: -------------------------------------------------------------------------------- 1 | package myConnection.higher.MyHMessage; 2 | 3 | import org.tron.core.net.message.MessageTypes; 4 | import org.tron.protos.Protocol; 5 | 6 | public class MyHDisconnectMessage extends MyTronMessage{ 7 | private Protocol.DisconnectMessage disconnectMessage; 8 | 9 | public MyHDisconnectMessage(byte type, byte[] rawData) throws Exception { 10 | super(type, rawData); 11 | this.disconnectMessage = Protocol.DisconnectMessage.parseFrom(this.data); 12 | } 13 | 14 | public MyHDisconnectMessage(byte[] data) throws Exception { 15 | super(MessageTypes.P2P_DISCONNECT.asByte(), data); 16 | this.disconnectMessage = Protocol.DisconnectMessage.parseFrom(data); 17 | } 18 | 19 | public MyHDisconnectMessage(Protocol.ReasonCode reasonCode) { 20 | this.disconnectMessage = Protocol.DisconnectMessage 21 | .newBuilder() 22 | .setReason(reasonCode) 23 | .build(); 24 | this.type = MessageTypes.P2P_DISCONNECT.asByte(); 25 | this.data = this.disconnectMessage.toByteArray(); 26 | } 27 | 28 | public Protocol.ReasonCode getReason() { 29 | return this.disconnectMessage.getReason(); 30 | } 31 | 32 | public Protocol.ReasonCode getReasonCode() { 33 | return disconnectMessage.getReason(); 34 | } 35 | 36 | @Override 37 | public String toString() { 38 | return new StringBuilder().append(super.toString()).append("reason: ") 39 | .append(this.disconnectMessage.getReason()).toString(); 40 | } 41 | 42 | @Override 43 | public Class getAnswerMessage() { 44 | return null; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/myConnection/higher/MyHMessage/MyHBlockInventoryMessage.java: -------------------------------------------------------------------------------- 1 | package myConnection.higher.MyHMessage; 2 | 3 | import org.tron.core.capsule.BlockCapsule.BlockId; 4 | import org.tron.core.net.message.MessageTypes; 5 | import org.tron.protos.Protocol.BlockInventory; 6 | 7 | import java.util.ArrayList; 8 | import java.util.List; 9 | import java.util.stream.Collectors; 10 | 11 | public class MyHBlockInventoryMessage extends MyTronMessage { 12 | 13 | protected BlockInventory blockInventory; 14 | 15 | public MyHBlockInventoryMessage(byte[] data) throws Exception { 16 | super(data); 17 | this.type = MessageTypes.BLOCK_INVENTORY.asByte(); 18 | this.blockInventory = BlockInventory.parseFrom(data); 19 | } 20 | 21 | public MyHBlockInventoryMessage(List blockIds, BlockInventory.Type type) { 22 | BlockInventory.Builder invBuilder = BlockInventory.newBuilder(); 23 | blockIds.forEach(blockId -> { 24 | BlockInventory.BlockId.Builder b = BlockInventory.BlockId.newBuilder(); 25 | b.setHash(blockId.getByteString()); 26 | b.setNumber(blockId.getNum()); 27 | invBuilder.addIds(b); 28 | }); 29 | 30 | invBuilder.setType(type); 31 | blockInventory = invBuilder.build(); 32 | this.type = MessageTypes.BLOCK_INVENTORY.asByte(); 33 | this.data = blockInventory.toByteArray(); 34 | } 35 | 36 | @Override 37 | public Class getAnswerMessage() { 38 | return null; 39 | } 40 | 41 | private BlockInventory getBlockInventory() { 42 | return blockInventory; 43 | } 44 | 45 | public List getBlockIds() { 46 | return getBlockInventory().getIdsList().stream() 47 | .map(blockId -> new BlockId(blockId.getHash(), blockId.getNumber())) 48 | .collect(Collectors.toCollection(ArrayList::new)); 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Tron Script 2 | 本项目提供了用于测试波场p2p网络的脚本工具。功能包括波场节点发现协议消息收发和修改、节点连接、p2p网络消息监听和修改、p2p消息解析和打包等功能。 3 | ## Module 1-MyConnection 4 | 该模块实现了波场p2p网络中各种消息类型的构造、打包、解析功能,p2p连接的握手、连接信道保活等机制。该模块支持自定义消息、参数修改、消息中继流程自定义、常量更改。 5 | 6 | 该模块可以用于测试波场全节点连接、探测波场节点信息、调试波场全节点连接等。 7 | 8 | ### 编译 9 | 编译需要`git`和64位的`Oracle JDK 1.8`,其他版本的JDK尚不支持。`Windows`和`Linux`均可 10 | 11 | 1. clone仓库 12 | ```bash 13 | $ git clone https://github.com/klaypexwcf/tron_script.git 14 | $ cd ./src/myConnection 15 | $ javac MyChannelManager.java 16 | ``` 17 | 2. 在当前目录下创建一个名为`MANIFEST.MF`的文件 18 | 19 | 内容如下 20 | > Main-Class: myConnection.MyChannelManager 21 | 22 | 3. 打包文件 23 | ```bash 24 | $ jar cfm TronConnector.jar MANIFEST.MF MyChannelManager.class 25 | ``` 26 | ### 运行 27 | ```bash 28 | $ java -jar ./TronConnector.jar 29 | ``` 30 | 目前可选的命令行参数 31 | - --localId 指定本地模拟节点的nodeId 32 | - --remoteIp 指定需要连接的节点的nodeId 33 | - 后续将支持更多命令行参数... 34 | ## Module 2-MyDiscover 35 | 该模块实现了波场的节点发现协议中各种消息类型的构造、打包、解析,进而支持了波场节点中发现协议模块的模拟。 36 | 37 | 该模块可以用于调试波场全节点的节点表、探测收集波场p2p网络中节点的信息(包括IP、nodeId、区块高度等)。 38 | 39 | 40 | ### 编译 41 | 编译需要`git`和64位的`Oracle JDK 1.8`,其他版本的JDK尚不支持。`Windows`和`Linux`均可 42 | 43 | 1. clone仓库 44 | ```bash 45 | $ git clone https://github.com/klaypexwcf/tron_script.git 46 | $ cd ./src/myDiscover 47 | $ javac Main.java 48 | ``` 49 | 2. 在当前目录下创建一个名为`MANIFEST.MF`的文件 50 | 51 | 内容如下 52 | > Main-Class: myDiscover.Main 53 | 54 | 3. 打包文件 55 | ```bash 56 | $ jar cfm TronDiscoverSim.jar MANIFEST.MF Main.class 57 | ``` 58 | ### 运行 59 | ```bash 60 | $ java -jar ./TronDiscover.jar 61 | ``` 62 | 运行之后,会向指定的节点持续发送Kad_ping消息,每条消息中会包含不同的nodeId 63 | 64 | 目前可选的命令行参数 65 | - --localId 指定本地模拟节点的nodeId 66 | - --remoteIp 指定需要连接的节点的ipv4地址 67 | - --network 指定网络号 68 | - --localIp 指定需要绑定的本地网卡 69 | - 后续将支持更多命令行参数... 70 | -------------------------------------------------------------------------------- /src/myConnection/higher/MyHMessage/MyHBlockMessage.java: -------------------------------------------------------------------------------- 1 | package myConnection.higher.MyHMessage; 2 | 3 | import org.tron.common.overlay.message.Message; 4 | import org.tron.common.utils.Sha256Hash; 5 | import org.tron.core.capsule.BlockCapsule; 6 | import org.tron.core.capsule.BlockCapsule.BlockId; 7 | import org.tron.core.capsule.TransactionCapsule; 8 | import org.tron.core.net.message.MessageTypes; 9 | 10 | public class MyHBlockMessage extends MyTronMessage { 11 | 12 | private BlockCapsule block; 13 | 14 | public MyHBlockMessage(byte[] data) throws Exception { 15 | super(data); 16 | this.type = MessageTypes.BLOCK.asByte(); 17 | this.block = new BlockCapsule(getCodedInputStream(data)); 18 | if (Message.isFilter()) { 19 | Message.compareBytes(data, block.getInstance().toByteArray()); 20 | TransactionCapsule.validContractProto(block.getInstance().getTransactionsList()); 21 | } 22 | } 23 | 24 | public MyHBlockMessage(BlockCapsule block) { 25 | data = block.getData(); 26 | this.type = MessageTypes.BLOCK.asByte(); 27 | this.block = block; 28 | } 29 | 30 | public BlockId getBlockId() { 31 | return getBlockCapsule().getBlockId(); 32 | } 33 | 34 | public BlockCapsule getBlockCapsule() { 35 | return block; 36 | } 37 | 38 | @Override 39 | public Class getAnswerMessage() { 40 | return null; 41 | } 42 | 43 | @Override 44 | public Sha256Hash getMessageId() { 45 | return getBlockCapsule().getBlockId(); 46 | } 47 | 48 | @Override 49 | public boolean equals(Object obj) { 50 | return super.equals(obj); 51 | } 52 | 53 | @Override 54 | public int hashCode() { 55 | return super.hashCode(); 56 | } 57 | 58 | @Override 59 | public String toString() { 60 | return new StringBuilder().append(super.toString()).append(block.getBlockId().getString()) 61 | .append(", trx size: ").append(block.getTransactions().size()).append("\n").toString(); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/myConnection/message/MyStatusMessage.java: -------------------------------------------------------------------------------- 1 | package myConnection.message; 2 | 3 | import myDiscover.MyConfig; 4 | import org.tron.p2p.connection.ChannelManager; 5 | import org.tron.p2p.connection.message.MessageType; 6 | import org.tron.p2p.discover.Node; 7 | import org.tron.p2p.protos.Connect; 8 | import org.tron.p2p.protos.Discover; 9 | import org.tron.p2p.utils.NetUtil; 10 | 11 | public class MyStatusMessage extends MyMessage { 12 | private Connect.StatusMessage statusMessage; 13 | 14 | public MyStatusMessage(byte[] data) throws Exception { 15 | super(MessageType.STATUS, data); 16 | this.statusMessage = Connect.StatusMessage.parseFrom(data); 17 | } 18 | 19 | public MyStatusMessage() { 20 | super(MessageType.STATUS, null); 21 | Discover.Endpoint endpoint = MyConfig.getHomeNode(); 22 | this.statusMessage = Connect.StatusMessage.newBuilder() 23 | .setFrom(endpoint) 24 | .setMaxConnections(10000) 25 | .setCurrentConnections(ChannelManager.getChannels().size()) 26 | .setNetworkId(MyConfig.getNetwork()) 27 | .setTimestamp(System.currentTimeMillis()).build(); 28 | this.data = statusMessage.toByteArray(); 29 | System.out.println("new Status Msg with RemainConn:"+this.getRemainConnections()); 30 | } 31 | 32 | public int getNetworkId() { 33 | return this.statusMessage.getNetworkId(); 34 | } 35 | 36 | public int getVersion() { 37 | return this.statusMessage.getVersion(); 38 | } 39 | 40 | public int getRemainConnections() { 41 | return this.statusMessage.getMaxConnections() - this.statusMessage.getCurrentConnections(); 42 | } 43 | 44 | public long getTimestamp() { 45 | return this.statusMessage.getTimestamp(); 46 | } 47 | 48 | public Node getFrom() { 49 | return NetUtil.getNode(statusMessage.getFrom()); 50 | } 51 | 52 | @Override 53 | public String toString() { 54 | return "[StatusMessage: " + statusMessage; 55 | } 56 | 57 | @Override 58 | public boolean valid() { 59 | return NetUtil.validNode(getFrom()); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/myConnection/message/MyHelloMessage.java: -------------------------------------------------------------------------------- 1 | package myConnection.message; 2 | 3 | import myDiscover.MyConfig; 4 | import org.tron.p2p.connection.business.handshake.DisconnectCode; 5 | import org.tron.p2p.connection.message.MessageType; 6 | import org.tron.p2p.discover.Node; 7 | import org.tron.p2p.protos.Connect; 8 | import org.tron.p2p.protos.Discover; 9 | import org.tron.p2p.utils.NetUtil; 10 | 11 | public class MyHelloMessage extends MyMessage { 12 | private Connect.HelloMessage helloMessage; 13 | 14 | public MyHelloMessage(byte[] data) throws Exception { 15 | super(MessageType.HANDSHAKE_HELLO, data); 16 | this.helloMessage = Connect.HelloMessage.parseFrom(data); 17 | } 18 | 19 | public MyHelloMessage(DisconnectCode code, long time) { 20 | super(MessageType.HANDSHAKE_HELLO, null); 21 | Discover.Endpoint endpoint = MyConfig.getHomeNode(); 22 | this.helloMessage = Connect.HelloMessage.newBuilder() 23 | .setFrom(endpoint) 24 | .setNetworkId(MyConfig.getNetwork()) 25 | .setCode(code.getValue()) 26 | .setVersion(MyConfig.version) 27 | .setTimestamp(time).build(); 28 | this.data = helloMessage.toByteArray(); 29 | } 30 | 31 | public int getNetworkId() { 32 | return this.helloMessage.getNetworkId(); 33 | } 34 | 35 | public int getVersion() { 36 | return this.helloMessage.getVersion(); 37 | } 38 | 39 | public int getCode() { 40 | return this.helloMessage.getCode(); 41 | } 42 | 43 | public long getTimestamp() { 44 | return this.helloMessage.getTimestamp(); 45 | } 46 | 47 | public Node getFrom() { 48 | return NetUtil.getNode(helloMessage.getFrom()); 49 | } 50 | 51 | @Override 52 | public String toString() { 53 | return "[HelloMessage: " + helloMessage; 54 | } 55 | 56 | @Override 57 | public boolean valid() { 58 | return NetUtil.validNode(getFrom()); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/myDiscover/MyKadPongMessage.java: -------------------------------------------------------------------------------- 1 | package myDiscover; 2 | 3 | import org.tron.p2p.discover.Node; 4 | import org.tron.p2p.discover.message.MessageType; 5 | import org.tron.p2p.discover.message.kad.KadMessage; 6 | import org.tron.p2p.protos.Discover; 7 | import org.tron.p2p.utils.NetUtil; 8 | 9 | public class MyKadPongMessage extends KadMessage { 10 | private final Discover.PongMessage pongMessage; 11 | 12 | public MyKadPongMessage(byte[] data) throws Exception { 13 | super(MessageType.KAD_PONG, data); 14 | this.pongMessage = org.tron.p2p.protos.Discover.PongMessage.parseFrom(data); 15 | } 16 | 17 | public MyKadPongMessage(Node from) { 18 | super(MessageType.KAD_PONG, (byte[])null); 19 | Discover.Endpoint toEndpoint = getEndpointFromNode(from); 20 | this.pongMessage = org.tron.p2p.protos.Discover.PongMessage.newBuilder().setFrom(toEndpoint).setEcho(11111).setTimestamp(System.currentTimeMillis()).build(); 21 | this.data = this.pongMessage.toByteArray(); 22 | } 23 | 24 | /** 25 | * get default PongMsg 26 | */ 27 | public MyKadPongMessage(){ 28 | super(MessageType.KAD_PONG, (byte[])null); 29 | Discover.Endpoint toEndpoint = getEndpointFromNode(MyConfig.getFrom()); 30 | this.pongMessage = org.tron.p2p.protos.Discover.PongMessage.newBuilder().setFrom(toEndpoint).setEcho(11111).setTimestamp(System.currentTimeMillis()).build(); 31 | this.data = this.pongMessage.toByteArray(); 32 | } 33 | 34 | public int getNetworkId() { 35 | return this.pongMessage.getEcho(); 36 | } 37 | 38 | public long getTimestamp() { 39 | return this.pongMessage.getTimestamp(); 40 | } 41 | 42 | public Node getFrom() { 43 | return NetUtil.getNode(this.pongMessage.getFrom()); 44 | } 45 | 46 | public String toString() { 47 | return "[pongMessage: " + this.pongMessage; 48 | } 49 | 50 | public boolean valid() { 51 | return NetUtil.validNode(this.getFrom()); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/myDiscover/MyKadPingMessage.java: -------------------------------------------------------------------------------- 1 | package myDiscover; 2 | 3 | import org.tron.p2p.discover.Node; 4 | import org.tron.p2p.discover.message.MessageType; 5 | import org.tron.p2p.discover.message.kad.KadMessage; 6 | import org.tron.p2p.protos.Discover; 7 | import org.tron.p2p.utils.NetUtil; 8 | 9 | public class MyKadPingMessage extends KadMessage { 10 | private final Discover.PingMessage pingMessage; 11 | public MyKadPingMessage(Node from, Node to){ 12 | super(MessageType.KAD_PING, (byte[])null); 13 | Discover.Endpoint fromEndpoint = getEndpointFromNode(from); 14 | Discover.Endpoint toEndpoint = getEndpointFromNode(to); 15 | this.pingMessage = org.tron.p2p.protos.Discover.PingMessage.newBuilder().setVersion(11111).setFrom(fromEndpoint).setTo(toEndpoint).setTimestamp(System.currentTimeMillis()).build(); 16 | this.data = this.pingMessage.toByteArray(); 17 | } 18 | /** 19 | * get default PingMsg 20 | */ 21 | public MyKadPingMessage(){ 22 | super(MessageType.KAD_PING, (byte[])null); 23 | Discover.Endpoint fromEndpoint = getEndpointFromNode(MyConfig.getFrom()); 24 | Discover.Endpoint toEndpoint = getEndpointFromNode(MyConfig.getTo()); 25 | this.pingMessage = org.tron.p2p.protos.Discover.PingMessage.newBuilder().setVersion(11111).setFrom(fromEndpoint).setTo(toEndpoint).setTimestamp(System.currentTimeMillis()).build(); 26 | this.data = this.pingMessage.toByteArray(); 27 | } 28 | public int getNetworkId() 29 | { 30 | return this.pingMessage.getVersion(); 31 | } 32 | 33 | public Node getTo() { 34 | return NetUtil.getNode(this.pingMessage.getTo()); 35 | } 36 | 37 | public long getTimestamp() { 38 | return this.pingMessage.getTimestamp(); 39 | } 40 | 41 | public Node getFrom() { 42 | return NetUtil.getNode(this.pingMessage.getFrom()); 43 | } 44 | 45 | public String toString() { 46 | return "[pingMessage: " + this.pingMessage; 47 | } 48 | 49 | public boolean valid() { 50 | return NetUtil.validNode(this.getFrom()); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/myDiscover/MyP2pPacketDecoder.java: -------------------------------------------------------------------------------- 1 | package myDiscover; 2 | 3 | import com.google.protobuf.InvalidProtocolBufferException; 4 | import io.netty.buffer.ByteBuf; 5 | import io.netty.channel.ChannelHandlerContext; 6 | import io.netty.channel.socket.DatagramPacket; 7 | import io.netty.handler.codec.MessageToMessageDecoder; 8 | import org.tron.p2p.exception.P2pException; 9 | import org.tron.p2p.discover.message.Message; 10 | 11 | import java.util.List; 12 | 13 | public class MyP2pPacketDecoder extends MessageToMessageDecoder { 14 | private static final int MAXSIZE = 2048; 15 | @Override 16 | public void decode(ChannelHandlerContext ctx, DatagramPacket packet, List out) 17 | throws Exception { 18 | ByteBuf buf = packet.content(); 19 | int length = buf.readableBytes(); 20 | if (length <= 1 || length >= MAXSIZE) { 21 | //System.out.printf("UDP rcv bad packet, from {} length = {}\", ctx.channel().remoteAddress(), length"); 22 | return; 23 | } 24 | byte[] encoded = new byte[length]; 25 | buf.readBytes(encoded); 26 | try { 27 | UdpEvent event = new UdpEvent(Message.parse(encoded), packet.sender()); 28 | 29 | out.add(event); 30 | } catch (P2pException pe) { 31 | if (pe.getType().equals(P2pException.TypeEnum.BAD_MESSAGE)) { 32 | //log.error("Message validation failed, type {}, len {}, address {}", encoded[0], 33 | //encoded.length, packet.sender()); 34 | } else { 35 | // log.info("Parse msg failed, type {}, len {}, address {}", encoded[0], encoded.length, 36 | // packet.sender()); 37 | } 38 | } catch (InvalidProtocolBufferException e) { 39 | // log.warn("An exception occurred while parsing the message, type {}, len {}, address {}, " 40 | // + "data {}, cause: {}", encoded[0], encoded.length, packet.sender(), 41 | // ByteArray.toHexString(encoded), e.getMessage()); 42 | } catch (Exception e) { 43 | // log.error("An exception occurred while parsing the message, type {}, len {}, address {}, " 44 | // + "data {}", encoded[0], encoded.length, packet.sender(), 45 | // ByteArray.toHexString(encoded), e); 46 | } 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /src/myConnection/higher/MyHMessage/MyHInventoryMessage.java: -------------------------------------------------------------------------------- 1 | package myConnection.higher.MyHMessage; 2 | 3 | import org.tron.common.utils.Sha256Hash; 4 | import org.tron.core.net.message.MessageTypes; 5 | import org.tron.protos.Protocol.Inventory; 6 | import org.tron.protos.Protocol.Inventory.InventoryType; 7 | 8 | import java.util.Deque; 9 | import java.util.LinkedList; 10 | import java.util.List; 11 | import java.util.stream.Collectors; 12 | 13 | 14 | public class MyHInventoryMessage extends MyTronMessage { 15 | 16 | protected Inventory inv; 17 | 18 | public MyHInventoryMessage(byte[] data) throws Exception { 19 | super(data); 20 | this.type = MessageTypes.INVENTORY.asByte(); 21 | this.inv = Inventory.parseFrom(data); 22 | } 23 | 24 | public MyHInventoryMessage(Inventory inv) { 25 | this.inv = inv; 26 | this.type = MessageTypes.INVENTORY.asByte(); 27 | this.data = inv.toByteArray(); 28 | } 29 | 30 | public MyHInventoryMessage(List hashList, InventoryType type) { 31 | Inventory.Builder invBuilder = Inventory.newBuilder(); 32 | 33 | for (Sha256Hash hash : 34 | hashList) { 35 | invBuilder.addIds(hash.getByteString()); 36 | } 37 | invBuilder.setType(type); 38 | inv = invBuilder.build(); 39 | this.type = MessageTypes.INVENTORY.asByte(); 40 | this.data = inv.toByteArray(); 41 | } 42 | 43 | @Override 44 | public Class getAnswerMessage() { 45 | return null; 46 | } 47 | 48 | public Inventory getInventory() { 49 | return inv; 50 | } 51 | 52 | public MessageTypes getInvMessageType() { 53 | return getInventoryType().equals(InventoryType.BLOCK) ? MessageTypes.BLOCK : MessageTypes.TRX; 54 | 55 | } 56 | 57 | public InventoryType getInventoryType() { 58 | return inv.getType(); 59 | } 60 | 61 | @Override 62 | public String toString() { 63 | Deque hashes = new LinkedList<>(getHashList()); 64 | StringBuilder builder = new StringBuilder(); 65 | builder.append(super.toString()).append("invType: ").append(getInvMessageType()) 66 | .append(", size: ").append(hashes.size()) 67 | .append(", First hash: ").append(hashes.peekFirst()); 68 | if (hashes.size() > 1) { 69 | builder.append(", End hash: ").append(hashes.peekLast()); 70 | } 71 | return builder.toString(); 72 | } 73 | 74 | public List getHashList() { 75 | return getInventory().getIdsList().stream() 76 | .map(hash -> Sha256Hash.wrap(hash.toByteArray())) 77 | .collect(Collectors.toList()); 78 | } 79 | 80 | } 81 | -------------------------------------------------------------------------------- /tron_eclipse.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /src/myConnection/socket/MyP2pChannelInitializer.java: -------------------------------------------------------------------------------- 1 | package myConnection.socket; 2 | 3 | import myConnection.MyChannel; 4 | import myConnection.MyChannelManager; 5 | import io.netty.channel.ChannelFutureListener; 6 | import io.netty.channel.ChannelInitializer; 7 | import io.netty.channel.ChannelOption; 8 | import io.netty.channel.FixedRecvByteBufAllocator; 9 | import io.netty.channel.socket.nio.NioSocketChannel; 10 | import lombok.extern.slf4j.Slf4j; 11 | 12 | @Slf4j(topic = "MyP2pChannelInitializer") 13 | public class MyP2pChannelInitializer extends ChannelInitializer { 14 | private final String remoteId; 15 | 16 | private boolean peerDiscoveryMode = false; //only be true when channel is activated by detect service 17 | 18 | private boolean trigger = true; 19 | public MyP2pChannelInitializer(String remoteId, boolean peerDiscoveryMode, boolean trigger) { 20 | this.remoteId = remoteId; 21 | this.peerDiscoveryMode = peerDiscoveryMode; 22 | this.trigger = trigger; 23 | } 24 | 25 | @Override 26 | public void initChannel(NioSocketChannel ch) { 27 | try { 28 | final MyChannel channel = new MyChannel(); 29 | channel.init(ch.pipeline(), remoteId, peerDiscoveryMode); 30 | 31 | // limit the size of receiving buffer to 1024 32 | ch.config().setRecvByteBufAllocator(new FixedRecvByteBufAllocator(256 * 1024)); 33 | ch.config().setOption(ChannelOption.SO_RCVBUF, 256 * 1024); 34 | ch.config().setOption(ChannelOption.SO_BACKLOG, 1024); 35 | 36 | // be aware of channel closing 37 | ch.closeFuture().addListener((ChannelFutureListener) future -> { 38 | channel.setDisconnect(true); 39 | if (channel.isDiscoveryMode()) { 40 | //MyChannelManager.getNodeDetectService().notifyDisconnect(channel); 41 | } else { 42 | try { 43 | log.info("Close channel:{}", channel.getInetSocketAddress()); 44 | MyChannelManager.notifyDisconnect(channel); 45 | } finally { 46 | if (channel.getInetSocketAddress() != null && channel.isActive() && trigger) { 47 | //MyChannelManager.triggerConnect(channel.getInetSocketAddress()); 48 | } 49 | } 50 | } 51 | }); 52 | 53 | } catch (Exception e) { 54 | System.out.println("Unexpected initChannel error"+e); 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/myConnection/message/MyMessage.java: -------------------------------------------------------------------------------- 1 | package myConnection.message; 2 | 3 | import org.apache.commons.lang3.ArrayUtils; 4 | import org.tron.p2p.connection.message.MessageType; 5 | import org.tron.p2p.exception.P2pException; 6 | 7 | public abstract class MyMessage { 8 | protected MessageType type; 9 | protected byte[] data; 10 | 11 | public MyMessage(MessageType type, byte[] data) { 12 | this.type = type; 13 | this.data = data; 14 | } 15 | 16 | public MessageType getType() { 17 | return this.type; 18 | } 19 | 20 | public byte[] getData() { 21 | return this.data; 22 | } 23 | 24 | public byte[] getSendData() { 25 | return ArrayUtils.add(this.data, 0, type.getType()); 26 | } 27 | 28 | public abstract boolean valid(); 29 | 30 | public boolean needToLog() { 31 | return type.equals(MessageType.DISCONNECT) || type.equals(MessageType.HANDSHAKE_HELLO); 32 | } 33 | 34 | public static MyMessage parse(byte[] encode) throws P2pException { 35 | byte type = encode[0]; 36 | try { 37 | byte[] data = ArrayUtils.subarray(encode, 1, encode.length); 38 | MyMessage message; 39 | switch (MessageType.fromByte(type)) { 40 | case KEEP_ALIVE_PING: 41 | message = new MyPingMessage(data); 42 | break; 43 | case KEEP_ALIVE_PONG: 44 | message = new MyPongMessage(data); 45 | break; 46 | case HANDSHAKE_HELLO: 47 | message = new MyHelloMessage(data); 48 | break; 49 | case STATUS: 50 | message = new MyStatusMessage(data); 51 | break; 52 | case DISCONNECT: 53 | message = new MyP2pDisconnectMessage(data); 54 | break; 55 | default: 56 | throw new P2pException(P2pException.TypeEnum.NO_SUCH_MESSAGE, "type=" + type); 57 | } 58 | if (!message.valid()) { 59 | throw new P2pException(P2pException.TypeEnum.BAD_MESSAGE, "type=" + type); 60 | } 61 | return message; 62 | } catch (P2pException p2pException) { 63 | throw p2pException; 64 | } catch (Exception e) { 65 | throw new P2pException(P2pException.TypeEnum.BAD_MESSAGE, "type:" + type); 66 | } 67 | } 68 | 69 | @Override 70 | public String toString() { 71 | return "type: " + getType() + ", "; 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/myDiscover/MyMessageHandler.java: -------------------------------------------------------------------------------- 1 | package myDiscover; 2 | 3 | import io.netty.buffer.Unpooled; 4 | import io.netty.channel.ChannelHandlerContext; 5 | import io.netty.channel.SimpleChannelInboundHandler; 6 | import io.netty.channel.socket.nio.NioDatagramChannel; 7 | import io.netty.channel.socket.DatagramPacket; 8 | import io.netty.channel.Channel; 9 | import java.net.InetSocketAddress; 10 | import java.util.function.Consumer; 11 | 12 | public class MyMessageHandler extends SimpleChannelInboundHandler implements Consumer { 13 | private final Channel channel; 14 | private final MyEventHandler myEventHandler; 15 | 16 | public boolean isKeepSending() { 17 | return keepSending; 18 | } 19 | 20 | private boolean keepSending=true; 21 | 22 | public MyMessageHandler(NioDatagramChannel channel, MyEventHandler eventHandler) { 23 | this.channel = channel; 24 | this.myEventHandler = eventHandler; 25 | } 26 | 27 | @Override 28 | public void channelActive(ChannelHandlerContext ctx) throws Exception { 29 | myEventHandler.channelActivated(); 30 | } 31 | 32 | @Override 33 | public void channelRead0(ChannelHandlerContext ctx, UdpEvent udpEvent) { 34 | System.out.println("Rcv udp msg type " + udpEvent.getMessage().getType() + 35 | ", len " + udpEvent.getMessage().getSendData().length + 36 | " from " + udpEvent.getAddress()); 37 | myEventHandler.handleEvent(udpEvent); 38 | this.keepSending=false; 39 | } 40 | 41 | @Override 42 | public void accept(UdpEvent udpEvent) { 43 | System.out.println("Send udp msg type " + udpEvent.getMessage().getType() + 44 | ", len " + udpEvent.getMessage().getSendData().length + 45 | " to " + udpEvent.getAddress()); 46 | InetSocketAddress address = udpEvent.getAddress(); 47 | sendPacket(udpEvent.getMessage().getSendData(), address); 48 | } 49 | 50 | void sendPacket(byte[] wire, InetSocketAddress address) { 51 | DatagramPacket packet = new DatagramPacket(Unpooled.copiedBuffer(wire), address); 52 | channel.write(packet); 53 | channel.flush(); 54 | } 55 | 56 | @Override 57 | public void channelReadComplete(ChannelHandlerContext ctx) { 58 | ctx.flush(); 59 | } 60 | 61 | @Override 62 | public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { 63 | System.err.println("Exception caught in udp message handler, " + ctx.channel().remoteAddress() + " " + cause.getMessage()); 64 | ctx.close(); 65 | } 66 | } -------------------------------------------------------------------------------- /src/myConnection/higher/MyHMessage/MyHChainInventoryMessage.java: -------------------------------------------------------------------------------- 1 | package myConnection.higher.MyHMessage; 2 | 3 | import org.tron.core.capsule.BlockCapsule.BlockId; 4 | import org.tron.core.net.message.MessageTypes; 5 | import org.tron.protos.Protocol.ChainInventory; 6 | 7 | import java.util.ArrayList; 8 | import java.util.Deque; 9 | import java.util.LinkedList; 10 | import java.util.List; 11 | import java.util.stream.Collectors; 12 | 13 | public class MyHChainInventoryMessage extends MyTronMessage { 14 | 15 | protected ChainInventory chainInventory; 16 | 17 | public MyHChainInventoryMessage(byte[] data) throws Exception { 18 | super(data); 19 | this.type = MessageTypes.BLOCK_CHAIN_INVENTORY.asByte(); 20 | chainInventory = ChainInventory.parseFrom(data); 21 | } 22 | 23 | public MyHChainInventoryMessage(List blockIds, Long remainNum) { 24 | ChainInventory.Builder invBuilder = ChainInventory.newBuilder(); 25 | blockIds.forEach(blockId -> { 26 | ChainInventory.BlockId.Builder b = ChainInventory.BlockId.newBuilder(); 27 | b.setHash(blockId.getByteString()); 28 | b.setNumber(blockId.getNum()); 29 | invBuilder.addIds(b); 30 | }); 31 | 32 | invBuilder.setRemainNum(remainNum); 33 | chainInventory = invBuilder.build(); 34 | this.type = MessageTypes.BLOCK_CHAIN_INVENTORY.asByte(); 35 | this.data = chainInventory.toByteArray(); 36 | } 37 | 38 | @Override 39 | public Class getAnswerMessage() { 40 | return null; 41 | } 42 | 43 | private ChainInventory getChainInventory() { 44 | return chainInventory; 45 | } 46 | 47 | public List getBlockIds() { 48 | 49 | try { 50 | return getChainInventory().getIdsList().stream() 51 | .map(blockId -> new BlockId(blockId.getHash(), blockId.getNumber())) 52 | .collect(Collectors.toCollection(ArrayList::new)); 53 | } catch (Exception e) { 54 | logger.info("Failed to get blockIds of chain inventory message"); 55 | } 56 | return null; 57 | } 58 | 59 | public Long getRemainNum() { 60 | return getChainInventory().getRemainNum(); 61 | } 62 | 63 | @Override 64 | public String toString() { 65 | Deque blockIdWeGet = new LinkedList<>(getBlockIds()); 66 | StringBuilder sb = new StringBuilder(super.toString()); 67 | int size = blockIdWeGet.size(); 68 | sb.append("size: ").append(size); 69 | if (size >= 1) { 70 | sb.append(", first blockId: ").append(blockIdWeGet.peek().getString()); 71 | if (size > 1) { 72 | sb.append(", end blockId: ").append(blockIdWeGet.peekLast().getString()); 73 | } 74 | } 75 | sb.append(", remain_num: ").append(chainInventory.getRemainNum()); 76 | return sb.toString(); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /src/myConnection/socket/MyPeerServer.java: -------------------------------------------------------------------------------- 1 | package myConnection.socket; 2 | 3 | import myDiscover.MyConfig; 4 | import io.netty.bootstrap.ServerBootstrap; 5 | import io.netty.channel.ChannelFuture; 6 | import io.netty.channel.ChannelOption; 7 | import io.netty.channel.DefaultMessageSizeEstimator; 8 | import io.netty.channel.EventLoopGroup; 9 | import io.netty.channel.nio.NioEventLoopGroup; 10 | import io.netty.channel.socket.nio.NioServerSocketChannel; 11 | import io.netty.handler.logging.LoggingHandler; 12 | import org.apache.commons.lang3.concurrent.BasicThreadFactory; 13 | 14 | 15 | public class MyPeerServer { 16 | private ChannelFuture channelFuture; 17 | private boolean listening; 18 | 19 | public void init(){ 20 | int port = MyConfig.getFromPort(); 21 | if (port >0){ 22 | new Thread(() -> start(port),"PeerServer").start(); 23 | } 24 | } 25 | public void close(){ 26 | if (listening && channelFuture != null && channelFuture.channel().isOpen()) { 27 | try { 28 | System.out.println("Closing TCP server..."); 29 | channelFuture.channel().close().sync(); 30 | } catch (Exception e) { 31 | System.out.println("Closing TCP server failed."+e); 32 | } 33 | } 34 | } 35 | public void start(int port) { 36 | EventLoopGroup bossGroup = new NioEventLoopGroup(1, 37 | new BasicThreadFactory.Builder().namingPattern("peerBoss").build()); 38 | //if threads = 0, it is number of core * 2 39 | EventLoopGroup workerGroup = new NioEventLoopGroup(0, 40 | new BasicThreadFactory.Builder().namingPattern("peerWorker-%d").build()); 41 | MyP2pChannelInitializer p2pChannelInitializer = new MyP2pChannelInitializer("", false, true); 42 | try { 43 | ServerBootstrap b = new ServerBootstrap(); 44 | 45 | b.group(bossGroup, workerGroup); 46 | b.channel(NioServerSocketChannel.class); 47 | 48 | b.option(ChannelOption.MESSAGE_SIZE_ESTIMATOR, DefaultMessageSizeEstimator.DEFAULT); 49 | b.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, MyConfig.NODE_CONNECTION_TIMEOUT); 50 | 51 | b.handler(new LoggingHandler()); 52 | b.childHandler(p2pChannelInitializer); 53 | 54 | // Start the client. 55 | System.out.println("TCP listener started, bind port {}"+port); 56 | 57 | channelFuture = b.bind(port).sync(); 58 | 59 | listening = true; 60 | 61 | // Wait until the connection is closed. 62 | channelFuture.channel().closeFuture().sync(); 63 | 64 | System.out.println("TCP listener closed"); 65 | 66 | } catch (Exception e) { 67 | System.out.printf("Start TCP server failed"+ e); 68 | } finally { 69 | workerGroup.shutdownGracefully(); 70 | bossGroup.shutdownGracefully(); 71 | listening = false; 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /src/myConnection/keepalive/MyKeepAliveService.java: -------------------------------------------------------------------------------- 1 | package myConnection.keepalive; 2 | 3 | import myConnection.MessageProcess; 4 | import myConnection.MyChannel; 5 | import myConnection.MyChannelManager; 6 | import myConnection.message.MyMessage; 7 | import myConnection.message.MyPingMessage; 8 | import myConnection.message.MyPongMessage; 9 | import myDiscover.MyConfig; 10 | import org.apache.commons.lang3.concurrent.BasicThreadFactory; 11 | 12 | import java.util.concurrent.Executors; 13 | import java.util.concurrent.ScheduledExecutorService; 14 | import java.util.concurrent.TimeUnit; 15 | 16 | //import static org.tron.p2p.base.Parameter.KEEP_ALIVE_TIMEOUT; 17 | //import static org.tron.p2p.base.Parameter.PING_TIMEOUT; 18 | 19 | public class MyKeepAliveService implements MessageProcess { 20 | private final ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor( 21 | new BasicThreadFactory.Builder().namingPattern("keepAlive").build()); 22 | 23 | public void init() { 24 | executor.scheduleWithFixedDelay(() -> { 25 | try { 26 | long now = System.currentTimeMillis(); 27 | MyChannelManager.getChannels().values().stream() 28 | .filter(p -> !p.isDisconnect()) 29 | .forEach(p -> { 30 | if (p.waitForPong) { 31 | if (now - p.pingSent > MyConfig.KEEP_ALIVE_TIMEOUT) { 32 | // p.send(new MyP2pDisconnectMessage(Connect.DisconnectReason.PING_TIMEOUT)); 33 | // p.close(); 34 | } 35 | } else { 36 | if (now - p.getLastSendTime() > MyConfig.PING_TIMEOUT && p.isFinishHandshake()) { 37 | p.send(new MyPingMessage()); 38 | p.waitForPong = true; 39 | p.pingSent = now; 40 | } 41 | } 42 | //p.send(new MyPongMessage()); 43 | }); 44 | } catch (Exception t) { 45 | //log.error("Exception in keep alive task", t); 46 | } 47 | }, 2, 2, TimeUnit.SECONDS); 48 | } 49 | 50 | public void close() { 51 | executor.shutdown(); 52 | } 53 | 54 | @Override 55 | public void processMessage(MyChannel channel, MyMessage message) { 56 | switch (message.getType()) { 57 | case KEEP_ALIVE_PING: 58 | channel.send(new MyPongMessage()); 59 | try { 60 | TimeUnit.SECONDS.sleep(5); 61 | } catch (InterruptedException e) { 62 | throw new RuntimeException(e); 63 | } 64 | channel.send(new MyPongMessage()); 65 | break; 66 | case KEEP_ALIVE_PONG: 67 | channel.updateAvgLatency(System.currentTimeMillis() - channel.pingSent); 68 | channel.waitForPong = false; 69 | break; 70 | default: 71 | break; 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /src/myConnection/handshake/MyHandshakeService.java: -------------------------------------------------------------------------------- 1 | package myConnection.handshake; 2 | 3 | import myDiscover.MyConfig; 4 | import myConnection.MessageProcess; 5 | import myConnection.MyChannel; 6 | import myConnection.MyChannelManager; 7 | import myConnection.message.MyHelloMessage; 8 | import myConnection.message.MyMessage; 9 | import myConnection.message.MyP2pDisconnectMessage; 10 | import org.tron.p2p.connection.business.handshake.DisconnectCode; 11 | import org.tron.p2p.protos.Connect; 12 | 13 | import static org.tron.p2p.connection.ChannelManager.getDisconnectReason; 14 | 15 | public class MyHandshakeService implements MessageProcess { 16 | private final int networkId = MyConfig.getNetwork(); 17 | 18 | public void startHandshake(MyChannel channel) { 19 | sendHelloMsg(channel, DisconnectCode.NORMAL, channel.getStartTime()); 20 | } 21 | 22 | @Override 23 | public void processMessage(MyChannel channel, MyMessage message) { 24 | MyHelloMessage msg = (MyHelloMessage) message; 25 | 26 | if (channel.isFinishHandshake()) { 27 | //log.warn("Close channel {}, handshake is finished", channel.getInetSocketAddress()); 28 | channel.send(new MyP2pDisconnectMessage(Connect.DisconnectReason.DUP_HANDSHAKE)); 29 | channel.close(); 30 | return; 31 | } 32 | 33 | channel.setHelloMessage(msg); 34 | 35 | DisconnectCode code = MyChannelManager.processPeer(channel); 36 | if (code != DisconnectCode.NORMAL) { 37 | if (!channel.isActive()) { 38 | sendHelloMsg(channel, code, msg.getTimestamp()); 39 | } 40 | MyChannelManager.logDisconnectReason(channel, getDisconnectReason(code)); 41 | channel.close(); 42 | return; 43 | } 44 | 45 | MyChannelManager.updateNodeId(channel, msg.getFrom().getHexId()); 46 | if (channel.isDisconnect()) { 47 | return; 48 | } 49 | 50 | if (channel.isActive()) { 51 | if (msg.getCode() != DisconnectCode.NORMAL.getValue() 52 | || (msg.getNetworkId() != networkId && msg.getVersion() != networkId)) { 53 | DisconnectCode disconnectCode = DisconnectCode.forNumber(msg.getCode()); 54 | //v0.1 have version, v0.2 both have version and networkId 55 | 56 | MyChannelManager.logDisconnectReason(channel, getDisconnectReason(disconnectCode)); 57 | channel.close(); 58 | return; 59 | } 60 | } else { 61 | 62 | if (msg.getNetworkId() != networkId) { 63 | 64 | sendHelloMsg(channel, DisconnectCode.DIFFERENT_VERSION, msg.getTimestamp()); 65 | MyChannelManager.logDisconnectReason(channel, Connect.DisconnectReason.DIFFERENT_VERSION); 66 | channel.close(); 67 | return; 68 | } 69 | sendHelloMsg(channel, DisconnectCode.NORMAL, msg.getTimestamp()); 70 | } 71 | channel.setFinishHandshake(true); 72 | channel.updateAvgLatency(System.currentTimeMillis() - channel.getStartTime()); 73 | MyConfig.hp2pEventHandler.onConnect(channel); 74 | } 75 | 76 | private void sendHelloMsg(MyChannel channel, DisconnectCode code, long time) { 77 | MyHelloMessage helloMessage = new MyHelloMessage(code, time); 78 | channel.send(helloMessage); 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/myDiscover/Main.java: -------------------------------------------------------------------------------- 1 | package myDiscover; 2 | 3 | import io.netty.bootstrap.Bootstrap; 4 | import io.netty.channel.Channel; 5 | import io.netty.channel.ChannelInitializer; 6 | import io.netty.channel.nio.NioEventLoopGroup; 7 | import io.netty.channel.socket.nio.NioDatagramChannel; 8 | import io.netty.handler.codec.protobuf.ProtobufVarint32FrameDecoder; 9 | import io.netty.handler.codec.protobuf.ProtobufVarint32LengthFieldPrepender; 10 | import org.tron.p2p.stats.TrafficStats; 11 | 12 | import java.net.InetSocketAddress; 13 | 14 | public class Main { 15 | public static void main(String[] args) throws InterruptedException { 16 | MyConfig.init(); 17 | MyConfig.test(); 18 | MyEventHandler myEventHandler=new MyEventHandler(null); 19 | NioEventLoopGroup group = new NioEventLoopGroup(); 20 | try { 21 | Bootstrap bootstrap = new Bootstrap(); 22 | bootstrap.group(group) 23 | .channel(NioDatagramChannel.class) 24 | .handler(new ChannelInitializer() { 25 | @Override 26 | public void initChannel(NioDatagramChannel ch) 27 | throws Exception { 28 | ch.pipeline().addLast(TrafficStats.udp); 29 | ch.pipeline().addLast(new ProtobufVarint32LengthFieldPrepender()); 30 | ch.pipeline().addLast(new ProtobufVarint32FrameDecoder()); 31 | ch.pipeline().addLast(new MyP2pPacketDecoder()); 32 | MyMessageHandler messageHandler = new MyMessageHandler(ch, myEventHandler); 33 | myEventHandler.setMessageHandler(messageHandler); 34 | ch.pipeline().addLast(messageHandler); 35 | } 36 | }); 37 | 38 | // 启动客户端,绑定任意端口 39 | Channel channel = bootstrap.bind(MyConfig.getFromPort()).sync().channel(); 40 | 41 | //test 42 | NodeIdTable nodeIdTable1 =new NodeIdTable(); 43 | Byte[] byteId = Tool.toByteArray(MyConfig.getId()); 44 | nodeIdTable1.init(new NodeId(byteId)); 45 | //test 46 | 47 | // 构建自定义消息 48 | MyKadPingMessage PingMsg = new MyKadPingMessage(); 49 | 50 | // 构建 UdpEvent 51 | InetSocketAddress targetAddress = new InetSocketAddress(MyConfig.getToIp(), MyConfig.getToPort()); 52 | UdpEvent udpEvent = new UdpEvent(PingMsg, targetAddress); 53 | 54 | // 获取 MessageHandler 实例并发送消息 55 | MyMessageHandler myMessageHandler = (MyMessageHandler) channel.pipeline().last(); 56 | startSendingMessages(channel,myMessageHandler,udpEvent); 57 | 58 | // 等待通道关闭 59 | channel.closeFuture().await(); 60 | } finally { 61 | group.shutdownGracefully(); 62 | } 63 | } 64 | public static void startSendingMessages(Channel channel, MyMessageHandler messageHandler, UdpEvent udpEvent) { 65 | new Thread(() -> { 66 | try { 67 | while (messageHandler.isKeepSending()) { 68 | // 发送消息 69 | //System.out.println("Sending message..."); 70 | messageHandler.accept(udpEvent); 71 | 72 | // 设置发送间隔,避免过于频繁 73 | Thread.sleep(1000); // 每隔1秒发送一次 74 | } 75 | } catch (InterruptedException e) { 76 | e.printStackTrace(); 77 | } 78 | }).start(); 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/myConnection/socket/MyP2pProtobufVariant32FrameDecoder.java: -------------------------------------------------------------------------------- 1 | package myConnection.socket; 2 | 3 | import myDiscover.MyConfig; 4 | import myConnection.MyChannel; 5 | import myConnection.message.MyP2pDisconnectMessage; 6 | import io.netty.buffer.ByteBuf; 7 | import io.netty.channel.ChannelHandlerContext; 8 | import io.netty.handler.codec.ByteToMessageDecoder; 9 | import io.netty.handler.codec.CorruptedFrameException; 10 | import lombok.extern.slf4j.Slf4j; 11 | import org.tron.p2p.protos.Connect; 12 | 13 | import java.util.List; 14 | @Slf4j(topic = "net") 15 | public class MyP2pProtobufVariant32FrameDecoder extends ByteToMessageDecoder { 16 | private final MyChannel channel; 17 | 18 | public MyP2pProtobufVariant32FrameDecoder(MyChannel channel) { 19 | this.channel = channel; 20 | } 21 | 22 | private static int readRawVariant32(ByteBuf buffer) { 23 | if (!buffer.isReadable()) { 24 | return 0; 25 | } 26 | buffer.markReaderIndex(); 27 | byte tmp = buffer.readByte(); 28 | if (tmp >= 0) { 29 | return tmp; 30 | } else { 31 | int result = tmp & 127; 32 | if (!buffer.isReadable()) { 33 | buffer.resetReaderIndex(); 34 | return 0; 35 | } 36 | if ((tmp = buffer.readByte()) >= 0) { 37 | result |= tmp << 7; 38 | } else { 39 | result |= (tmp & 127) << 7; 40 | if (!buffer.isReadable()) { 41 | buffer.resetReaderIndex(); 42 | return 0; 43 | } 44 | if ((tmp = buffer.readByte()) >= 0) { 45 | result |= tmp << 14; 46 | } else { 47 | result |= (tmp & 127) << 14; 48 | if (!buffer.isReadable()) { 49 | buffer.resetReaderIndex(); 50 | return 0; 51 | } 52 | if ((tmp = buffer.readByte()) >= 0) { 53 | result |= tmp << 21; 54 | } else { 55 | result |= (tmp & 127) << 21; 56 | if (!buffer.isReadable()) { 57 | buffer.resetReaderIndex(); 58 | return 0; 59 | } 60 | result |= (tmp = buffer.readByte()) << 28; 61 | if (tmp < 0) { 62 | throw new CorruptedFrameException("malformed variant."); 63 | } 64 | } 65 | } 66 | } 67 | return result; 68 | } 69 | } 70 | 71 | @Override 72 | protected void decode(ChannelHandlerContext ctx, ByteBuf in, List out) { 73 | in.markReaderIndex(); 74 | int preIndex = in.readerIndex(); 75 | int length = readRawVariant32(in); 76 | if (length >= MyConfig.MAX_MESSAGE_LENGTH) { 77 | log.warn("Receive a big msg or not encoded msg, host : {}, msg length is : {}", 78 | ctx.channel().remoteAddress(), length); 79 | in.clear(); 80 | channel.send(new MyP2pDisconnectMessage(Connect.DisconnectReason.BAD_MESSAGE)); 81 | channel.close(); 82 | return; 83 | } 84 | if (preIndex == in.readerIndex()) { 85 | return; 86 | } 87 | if (length < 0) { 88 | throw new CorruptedFrameException("negative length: " + length); 89 | } 90 | 91 | if (in.readableBytes() < length) { 92 | in.resetReaderIndex(); 93 | } else { 94 | out.add(in.readRetainedSlice(length)); 95 | } 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /src/myConnection/socket/MyMessageHandler.java: -------------------------------------------------------------------------------- 1 | package myConnection.socket; 2 | 3 | import myConnection.MyChannel; 4 | import myConnection.MyChannelManager; 5 | import myConnection.message.MyP2pDisconnectMessage; 6 | import myConnection.message.MyStatusMessage; 7 | import io.netty.buffer.ByteBuf; 8 | import io.netty.channel.ChannelHandlerContext; 9 | import io.netty.handler.codec.ByteToMessageDecoder; 10 | import lombok.extern.slf4j.Slf4j; 11 | import org.tron.p2p.connection.business.upgrade.UpgradeController; 12 | import org.tron.p2p.exception.P2pException; 13 | import org.tron.p2p.protos.Connect; 14 | import org.tron.p2p.utils.ByteArray; 15 | 16 | import java.util.List; 17 | 18 | @Slf4j(topic = "net") 19 | public class MyMessageHandler extends ByteToMessageDecoder { 20 | private final MyChannel channel; 21 | 22 | public MyMessageHandler(MyChannel channel) { 23 | this.channel = channel; 24 | } 25 | 26 | @Override 27 | public void handlerAdded(ChannelHandlerContext ctx) { 28 | } 29 | 30 | @Override 31 | public void channelActive(ChannelHandlerContext ctx) { 32 | log.info("Channel active, {}", ctx.channel().remoteAddress()); 33 | //System.out.println("Channel active, " + ctx.channel().remoteAddress()); 34 | channel.setChannelHandlerContext(ctx); 35 | if (channel.isActive()) { 36 | //System.out.println("Channel IS active, " + ctx.channel().remoteAddress()); 37 | if (channel.isDiscoveryMode()) { 38 | //System.out.println("\\u001B[31m Channel is discv mode, " + ctx.channel().remoteAddress()+"\\u001B[0m"); 39 | channel.send(new MyStatusMessage()); 40 | } else { 41 | //System.out.println("Channel isn't discv mode, " + ctx.channel().remoteAddress()); 42 | MyChannelManager.getHandshakeService().startHandshake(channel); 43 | } 44 | } 45 | } 46 | 47 | @Override 48 | protected void decode(ChannelHandlerContext ctx, ByteBuf buffer, List out) { 49 | byte[] data = new byte[buffer.readableBytes()]; 50 | buffer.readBytes(data); 51 | try { 52 | if (channel.isFinishHandshake()) { 53 | data = UpgradeController.decodeReceiveData(channel.getVersion(), data); 54 | } 55 | MyChannelManager.processMessage(channel, data); 56 | } catch (Exception e) { 57 | if (e instanceof P2pException) { 58 | P2pException pe = (P2pException) e; 59 | Connect.DisconnectReason disconnectReason; 60 | switch (pe.getType()) { 61 | case EMPTY_MESSAGE: 62 | disconnectReason = Connect.DisconnectReason.EMPTY_MESSAGE; 63 | break; 64 | case BAD_PROTOCOL: 65 | disconnectReason = Connect.DisconnectReason.BAD_PROTOCOL; 66 | break; 67 | case NO_SUCH_MESSAGE: 68 | disconnectReason = Connect.DisconnectReason.NO_SUCH_MESSAGE; 69 | break; 70 | case BAD_MESSAGE: 71 | case PARSE_MESSAGE_FAILED: 72 | case MESSAGE_WITH_WRONG_LENGTH: 73 | case TYPE_ALREADY_REGISTERED: 74 | disconnectReason = Connect.DisconnectReason.BAD_MESSAGE; 75 | break; 76 | default: 77 | disconnectReason = Connect.DisconnectReason.UNKNOWN; 78 | } 79 | channel.send(new MyP2pDisconnectMessage(disconnectReason)); 80 | } 81 | channel.processException(e); 82 | } catch (Throwable t) { 83 | log.error("Decode message from {} failed, message:{}", channel.getInetSocketAddress(), 84 | ByteArray.toHexString(data)); 85 | throw t; 86 | } 87 | } 88 | 89 | @Override 90 | public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { 91 | channel.processException(cause); 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /src/myConnection/socket/MyPeerClient.java: -------------------------------------------------------------------------------- 1 | package myConnection.socket; 2 | 3 | import myDiscover.MyConfig; 4 | import myConnection.MyChannelManager; 5 | import io.netty.bootstrap.Bootstrap; 6 | import io.netty.channel.*; 7 | import io.netty.channel.nio.NioEventLoopGroup; 8 | import io.netty.channel.socket.nio.NioSocketChannel; 9 | import lombok.extern.slf4j.Slf4j; 10 | import org.apache.commons.lang3.concurrent.BasicThreadFactory; 11 | import org.bouncycastle.util.encoders.Hex; 12 | import org.tron.p2p.discover.Node; 13 | import org.tron.p2p.utils.NetUtil; 14 | @Slf4j 15 | public class MyPeerClient { 16 | private EventLoopGroup workerGroup; 17 | 18 | public void init() { 19 | workerGroup = new NioEventLoopGroup(0, 20 | new BasicThreadFactory.Builder().namingPattern("peerClient-%d").build()); 21 | } 22 | 23 | public void close() { 24 | workerGroup.shutdownGracefully(); 25 | workerGroup.terminationFuture().syncUninterruptibly(); 26 | } 27 | 28 | public void connect(String host, int port, String remoteId) { 29 | try { 30 | ChannelFuture f = connectAsync(host, port, remoteId, false, false); 31 | if (f != null) { 32 | f.sync().channel().closeFuture().sync(); 33 | } 34 | } catch (Exception e) { 35 | //log.warn("PeerClient can't connect to {}:{} ({})", host, port, e.getMessage()); 36 | } 37 | } 38 | 39 | public ChannelFuture connect(Node node, ChannelFutureListener future) { 40 | ChannelFuture channelFuture = connectAsync( 41 | node.getInetSocketAddressV4().getAddress().getHostAddress(), 42 | node.getPort(), 43 | node.getId() == null ? Hex.toHexString(NetUtil.getNodeId()) : node.getHexId(), false, 44 | false); 45 | if (MyChannelManager.isShutdown) { 46 | return null; 47 | } 48 | if (channelFuture != null && future != null) { 49 | channelFuture.addListener(future); 50 | } 51 | return channelFuture; 52 | } 53 | 54 | public ChannelFuture connectAsync(Node node, boolean discoveryMode) { 55 | log.info("entering func connectAsync1"); 56 | ChannelFuture channelFuture = 57 | connectAsync(node.getInetSocketAddressV4().getAddress().getHostAddress(), 58 | node.getPort(), 59 | node.getId() == null ? Hex.toHexString(NetUtil.getNodeId()) : node.getHexId(), 60 | discoveryMode, true); 61 | if (MyChannelManager.isShutdown) { 62 | return null; 63 | } 64 | if (channelFuture != null) { 65 | channelFuture.addListener((ChannelFutureListener) future -> { 66 | if (!future.isSuccess()) { 67 | log.warn("Connect to peer {} fail, cause:{}", node.getInetSocketAddressV4(), 68 | future.cause().getMessage()); 69 | future.channel().close(); 70 | //MyChannelManager.getPeerClient().connectAsync(node,false); 71 | // if (!discoveryMode) { 72 | // MyChannelManager.triggerConnect(node.getPreferInetSocketAddress()); 73 | //} 74 | } 75 | }); 76 | channelFuture.channel().closeFuture().addListener(future -> { 77 | Throwable cause = future.cause(); 78 | log.info("channel {} closed ", node.getInetSocketAddressV4()); 79 | if (cause != null) { 80 | log.warn("Channel {} closed due to: {}", node.getInetSocketAddressV4(), cause.getMessage(), cause); 81 | } else { 82 | log.info("Channel {} closed normally.", node.getInetSocketAddressV4()); 83 | } 84 | try { 85 | // 使当前线程暂停60秒,即tron默认的60秒BANTIME 86 | Thread.sleep(60000); 87 | } catch (InterruptedException e) { 88 | log.error("exception caught ",e); 89 | } 90 | 91 | MyChannelManager.getPeerClient().connectAsync(node,false); 92 | }); 93 | } 94 | return channelFuture; 95 | } 96 | 97 | private ChannelFuture connectAsync(String host, int port, String remoteId, 98 | boolean discoveryMode, boolean trigger) { 99 | log.info("entering func connectAsync2"); 100 | MyP2pChannelInitializer p2pChannelInitializer = new MyP2pChannelInitializer(remoteId, 101 | discoveryMode, trigger); 102 | 103 | Bootstrap b = new Bootstrap(); 104 | b.group(workerGroup); 105 | b.channel(NioSocketChannel.class); 106 | b.option(ChannelOption.SO_KEEPALIVE, true); 107 | b.option(ChannelOption.MESSAGE_SIZE_ESTIMATOR, DefaultMessageSizeEstimator.DEFAULT); 108 | b.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, MyConfig.NODE_CONNECTION_TIMEOUT); 109 | b.remoteAddress(host, port); 110 | b.handler(p2pChannelInitializer); 111 | if (MyChannelManager.isShutdown) { 112 | return null; 113 | } 114 | return b.connect(); 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /src/myConnection/MyHP2pEventHandlerImpl.java: -------------------------------------------------------------------------------- 1 | package myConnection; 2 | 3 | import myDiscover.Tool; 4 | import myConnection.higher.H_handshake.MyHHandshake; 5 | import myConnection.higher.H_keepalive.MyHKeepAlive; 6 | import myConnection.higher.MyHMessage.MyHDisconnectMessage; 7 | import myConnection.higher.MyHMessage.MyHHelloMessage; 8 | import myConnection.higher.MyHMessage.MyTronMessage; 9 | import lombok.extern.slf4j.Slf4j; 10 | import org.tron.core.exception.P2pException; 11 | import org.tron.core.net.message.MessageTypes; 12 | import org.tron.protos.Protocol; 13 | 14 | import java.util.Set; 15 | 16 | @Slf4j 17 | public class MyHP2pEventHandlerImpl extends MyP2pEventHandler { 18 | private MyHHandshake handshake; 19 | public MyHP2pEventHandlerImpl() { 20 | super(); 21 | } 22 | 23 | @Override 24 | public void onConnect(MyChannel channel) { 25 | MyHHandshake.startHandshake(channel); 26 | super.onConnect(channel); 27 | } 28 | 29 | @Override 30 | public void onDisconnect(MyChannel channel) { 31 | super.onDisconnect(channel); 32 | } 33 | 34 | @Override 35 | public void onMessage(MyChannel channel, byte[] data) { 36 | super.onMessage(channel, data); 37 | //log.info("received msg from peer {}",channel.getInetSocketAddress()); 38 | processMessage(channel,data); 39 | } 40 | private void processMessage(MyChannel channel, byte[] data) { 41 | long startTime = System.currentTimeMillis(); 42 | MyTronMessage msg = null; 43 | MessageTypes type = null; 44 | try { 45 | msg = Tool.create(data); 46 | type = msg.getType(); 47 | log.info("Receive message from peer: {}, {}", channel.getInetSocketAddress(), msg); 48 | switch (type) { 49 | case P2P_PING: 50 | case P2P_PONG: 51 | MyHKeepAlive.processMessage(channel, msg); 52 | break; 53 | case P2P_HELLO: 54 | MyHHandshake.processHelloMessage(channel, (MyHHelloMessage) msg); 55 | break; 56 | case P2P_DISCONNECT: 57 | channel.close(); 58 | log.info("received disconnect msg from channel {} with cause {}", channel.getInetSocketAddress(), ((MyHDisconnectMessage) msg).getReason()); 59 | break; 60 | case SYNC_BLOCK_CHAIN: 61 | //syncBlockChainMsgHandler.processMessage(peer, msg); 62 | break; 63 | case BLOCK_CHAIN_INVENTORY: 64 | //chainInventoryMsgHandler.processMessage(peer, msg); 65 | break; 66 | case INVENTORY: 67 | //inventoryMsgHandler.processMessage(peer, msg); 68 | break; 69 | case FETCH_INV_DATA: 70 | //fetchInvDataMsgHandler.processMessage(peer, msg); 71 | break; 72 | case BLOCK: 73 | //blockMsgHandler.processMessage(peer, msg); 74 | break; 75 | case TRXS: 76 | //transactionsMsgHandler.processMessage(peer, msg); 77 | break; 78 | case PBFT_COMMIT_MSG: 79 | //pbftDataSyncHandler.processMessage(peer, msg); 80 | break; 81 | default: 82 | throw new P2pException(P2pException.TypeEnum.NO_SUCH_MESSAGE, msg.getType().toString()); 83 | } 84 | } catch (Exception e) { 85 | processException(channel, msg, e); 86 | } 87 | } 88 | @Override 89 | public Set getMessageTypes() { 90 | return super.getMessageTypes(); 91 | } 92 | public void processException(MyChannel channel,MyTronMessage msg,Exception ex){ 93 | Protocol.ReasonCode code; 94 | if (ex instanceof P2pException) { 95 | P2pException.TypeEnum type = ((P2pException) ex).getType(); 96 | switch (type) { 97 | case BAD_TRX: 98 | code = Protocol.ReasonCode.BAD_TX; 99 | break; 100 | case BAD_BLOCK: 101 | code = Protocol.ReasonCode.BAD_BLOCK; 102 | break; 103 | case NO_SUCH_MESSAGE: 104 | code = Protocol.ReasonCode.NO_SUCH_MESSAGE; 105 | break; 106 | case BAD_MESSAGE: 107 | code = Protocol.ReasonCode.BAD_PROTOCOL; 108 | break; 109 | case SYNC_FAILED: 110 | code = Protocol.ReasonCode.SYNC_FAIL; 111 | break; 112 | case UNLINK_BLOCK: 113 | code = Protocol.ReasonCode.UNLINKABLE; 114 | break; 115 | case DB_ITEM_NOT_FOUND: 116 | code = Protocol.ReasonCode.FETCH_FAIL; 117 | break; 118 | default: 119 | code = Protocol.ReasonCode.UNKNOWN; 120 | break; 121 | } 122 | if (type.equals(P2pException.TypeEnum.BAD_MESSAGE)) { 123 | log.error("Message from {} process failed, {} \n type: ({})", 124 | channel.getInetSocketAddress(), msg, type, ex); 125 | } else { 126 | log.warn("Message from {} process failed, {} \n type: ({}), detail: {}", 127 | channel.getInetSocketAddress(), msg, type, ex.getMessage()); 128 | } 129 | } else { 130 | code = Protocol.ReasonCode.UNKNOWN; 131 | log.warn("Message from {} process failed, {}", 132 | channel.getInetSocketAddress(), msg, ex); 133 | } 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /src/myConnection/higher/H_handshake/MyHHandshake.java: -------------------------------------------------------------------------------- 1 | package myConnection.higher.H_handshake; 2 | 3 | import lombok.extern.slf4j.Slf4j; 4 | import myConnection.MyChannel; 5 | import myConnection.MyChannelManager; 6 | import myConnection.higher.MyHMessage.MyHDisconnectMessage; 7 | import myConnection.higher.MyHMessage.MyHHelloMessage; 8 | import myDiscover.MyConfig; 9 | import org.tron.p2p.utils.ByteArray; 10 | import org.tron.protos.Protocol; 11 | @Slf4j 12 | public class MyHHandshake { 13 | 14 | public static void startHandshake(MyChannel channel) { 15 | sendHelloMessage(channel); 16 | } 17 | public static void processHelloMessage(MyChannel channel, MyHHelloMessage msg) { 18 | // if (MyConfig.getHelloMessageReceive()!= null) { 19 | // log.warn("Peer {} receive dup hello message", channel.getInetSocketAddress()); 20 | // channel.send((new MyHDisconnectMessage(Protocol.ReasonCode.DUPLICATE_PEER).getSendBytes())); 21 | // channel.close(); 22 | // return; 23 | // } 24 | 25 | MyChannelManager.updateNodeId(channel, msg.getFrom().getHexId()); 26 | // if (peer.isDisconnect()) { 27 | // logger.info("Duplicate Peer {}", peer.getInetSocketAddress()); 28 | // peer.disconnect(ReasonCode.DUPLICATE_PEER); 29 | // return; 30 | // } 31 | 32 | if (!msg.valid()) { 33 | log.warn("Peer {} invalid hello message parameters, GenesisBlockId: {}, SolidBlockId: {}, " 34 | + "HeadBlockId: {}, address: {}, sig: {}, codeVersion: {}", 35 | channel.getInetSocketAddress(), 36 | ByteArray.toHexString(msg.getInstance().getGenesisBlockId().getHash().toByteArray()), 37 | ByteArray.toHexString(msg.getInstance().getSolidBlockId().getHash().toByteArray()), 38 | ByteArray.toHexString(msg.getInstance().getHeadBlockId().getHash().toByteArray()), 39 | msg.getInstance().getAddress().toByteArray().length, 40 | msg.getInstance().getSignature().toByteArray().length, 41 | msg.getInstance().getCodeVersion().toByteArray().length); 42 | channel.send((new MyHDisconnectMessage(Protocol.ReasonCode.UNEXPECTED_IDENTITY).getSendBytes())); 43 | channel.close(); 44 | return; 45 | } 46 | 47 | log.info("received P2P_HELLO with lowestBlockNum {}, GenesisBlockId {}, SolidBlockId {}", 48 | msg.getLowestBlockNum(), 49 | msg.getGenesisBlockId().getString(), 50 | msg.getSolidBlockId().getString() 51 | ); 52 | //peer.setAddress(msg.getHelloMessage().getAddress()); 53 | 54 | // if (!relayService.checkHelloMessage(msg, peer.getChannel())) { 55 | // peer.disconnect(ReasonCode.UNEXPECTED_IDENTITY); 56 | // return; 57 | // } 58 | // 59 | // long headBlockNum = chainBaseManager.getHeadBlockNum(); 60 | // long lowestBlockNum = msg.getLowestBlockNum(); 61 | // if (lowestBlockNum > headBlockNum) { 62 | // logger.info("Peer {} miss block, lowestBlockNum:{}, headBlockNum:{}", 63 | // peer.getInetSocketAddress(), lowestBlockNum, headBlockNum); 64 | // peer.disconnect(ReasonCode.LIGHT_NODE_SYNC_FAIL); 65 | // return; 66 | // } 67 | // 68 | // if (msg.getVersion() != Args.getInstance().getNodeP2pVersion()) { 69 | // logger.info("Peer {} different p2p version, peer->{}, me->{}", 70 | // peer.getInetSocketAddress(), msg.getVersion(), 71 | // Args.getInstance().getNodeP2pVersion()); 72 | // peer.disconnect(ReasonCode.INCOMPATIBLE_VERSION); 73 | // return; 74 | // } 75 | // 76 | // if (!Arrays.equals(chainBaseManager.getGenesisBlockId().getBytes(), 77 | // msg.getGenesisBlockId().getBytes())) { 78 | // logger.info("Peer {} different genesis block, peer->{}, me->{}", 79 | // peer.getInetSocketAddress(), 80 | // msg.getGenesisBlockId().getString(), 81 | // chainBaseManager.getGenesisBlockId().getString()); 82 | // peer.disconnect(ReasonCode.INCOMPATIBLE_CHAIN); 83 | // return; 84 | // } 85 | // 86 | // if (chainBaseManager.getSolidBlockId().getNum() >= msg.getSolidBlockId().getNum() 87 | // && !chainBaseManager.containBlockInMainChain(msg.getSolidBlockId())) { 88 | // logger.info("Peer {} different solid block, peer->{}, me->{}", 89 | // peer.getInetSocketAddress(), 90 | // msg.getSolidBlockId().getString(), 91 | // chainBaseManager.getSolidBlockId().getString()); 92 | // peer.disconnect(ReasonCode.FORKED); 93 | // return; 94 | // } 95 | // 96 | // if (msg.getHeadBlockId().getNum() < chainBaseManager.getHeadBlockId().getNum() 97 | // && peer.getInetSocketAddress().equals(effectiveCheckService.getCur())) { 98 | // logger.info("Peer's head block {} is below than we, peer->{}, me->{}", 99 | // peer.getInetSocketAddress(), msg.getHeadBlockId().getNum(), 100 | // chainBaseManager.getHeadBlockId().getNum()); 101 | // peer.disconnect(ReasonCode.BELOW_THAN_ME); 102 | // return; 103 | // } 104 | 105 | MyConfig.setHelloMessageReceive(msg); 106 | 107 | channel.updateAvgLatency( 108 | System.currentTimeMillis() - channel.getStartTime()); 109 | //PeerManager.sortPeers(); 110 | //peer.onConnect(); 111 | } 112 | 113 | private static void sendHelloMessage(MyChannel channel) { 114 | MyHHelloMessage message = new MyHHelloMessage(); 115 | //relayService.fillHelloMessage(message, peer.getChannel()); 116 | log.info("send P2P_HELLO to channel {}",channel.getInetSocketAddress()); 117 | log.info("My P2P Hello {}",message); 118 | channel.send(message.getSendBytes()); 119 | channel.setHHelloMessage(message); 120 | MyConfig.setHelloMessageSend(message); 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /src/myDiscover/Tool.java: -------------------------------------------------------------------------------- 1 | package myDiscover; 2 | 3 | import com.google.protobuf.ByteString; 4 | import myConnection.higher.MyHMessage.*; 5 | import org.apache.commons.lang3.ArrayUtils; 6 | import org.tron.core.exception.P2pException; 7 | import org.tron.core.net.message.MessageTypes; 8 | 9 | import java.security.SecureRandom; 10 | import java.util.Base64; 11 | 12 | public class Tool { 13 | public static final String DATA_LEN=", len="; 14 | 15 | public static boolean[] byteArrayToBitArray(Byte[] byteArray) { 16 | int byteLength = byteArray.length; 17 | boolean[] bitArray = new boolean[byteLength * 8]; 18 | 19 | for (int i = 0; i < byteLength; i++) { 20 | for (int bit = 0; bit < 8; bit++) { 21 | // 将每个字节的每一位提取出来,并存储在位数组中 22 | bitArray[i * 8 + bit] = (byteArray[i] & (1 << (7 - bit))) != 0; 23 | } 24 | } 25 | 26 | return bitArray; 27 | } 28 | public static void copyFirstIBits(boolean[] source, boolean[] destination, int i) { 29 | if (source == null || destination == null) { 30 | throw new IllegalArgumentException("源数组和目标数组不能为空。"); 31 | } 32 | if (i < 0) { 33 | throw new IllegalArgumentException("要复制的位数 i 不能为负。"); 34 | } 35 | if (source.length < i) { 36 | throw new IllegalArgumentException("源数组的长度不足以复制 " + i + " 位。"); 37 | } 38 | if (destination.length < i) { 39 | throw new IllegalArgumentException("目标数组的长度不足以复制 " + i + " 位。"); 40 | } 41 | 42 | System.arraycopy(source, 0, destination, 0, i); 43 | } 44 | public static Byte[] bitArrayToByteArray(boolean[] bitArray) { 45 | if (bitArray.length % 8 != 0) { 46 | throw new IllegalArgumentException("位数组的长度必须是8的倍数。"); 47 | } 48 | 49 | int byteLength = bitArray.length / 8; 50 | Byte[] byteArray = new Byte[byteLength]; 51 | 52 | for (int i = 0; i < byteLength; i++) { 53 | byte b = 0; 54 | for (int bit = 0; bit < 8; bit++) { 55 | if (bitArray[i * 8 + bit]) { 56 | b |= (1 << (7 - bit)); 57 | } 58 | } 59 | byteArray[i] = b; 60 | } 61 | 62 | return byteArray; 63 | } 64 | public static byte[] decodeFromBase64(String base64Str) { 65 | return Base64.getDecoder().decode(base64Str); 66 | } 67 | public static String encodeToBase64(byte[] data) { 68 | return Base64.getEncoder().encodeToString(data); 69 | } 70 | public static Byte[] toByteArray(byte[] byteArray) { 71 | // 创建一个新的 Byte[] 数组,长度与 byteArray 相同 72 | Byte[] byteObjectArray = new Byte[byteArray.length]; 73 | 74 | // 将 byte[] 中的每个元素转换为 Byte 对象,并存储在 Byte[] 中 75 | for (int i = 0; i < byteArray.length; i++) { 76 | byteObjectArray[i] = byteArray[i]; // 自动装箱 77 | } 78 | 79 | return byteObjectArray; 80 | } 81 | public static MyTronMessage create(byte[] data) throws Exception { 82 | boolean isException = false; 83 | try { 84 | byte type = data[0]; 85 | byte[] rawData = ArrayUtils.subarray(data, 1, data.length); 86 | return create(type, rawData); 87 | } catch (final P2pException e) { 88 | isException = true; 89 | throw e; 90 | } catch (final Exception e) { 91 | isException = true; 92 | throw new P2pException(P2pException.TypeEnum.PARSE_MESSAGE_FAILED, 93 | "type=" + data[0] + DATA_LEN + data.length + ", error msg: " + e.getMessage()); 94 | } finally { 95 | if (isException) { 96 | //MetricsUtil.counterInc(MetricsKey.NET_ERROR_PROTO_COUNT); 97 | } 98 | } 99 | } 100 | private static MyTronMessage create(byte type, byte[] packed) throws Exception { 101 | MessageTypes receivedTypes = MessageTypes.fromByte(type); 102 | if (receivedTypes == null) { 103 | throw new P2pException(P2pException.TypeEnum.NO_SUCH_MESSAGE, 104 | "type=" + type + DATA_LEN + packed.length); 105 | } 106 | switch (receivedTypes) { 107 | case P2P_HELLO: 108 | return new MyHHelloMessage(packed); 109 | case P2P_DISCONNECT: 110 | return new MyHDisconnectMessage(packed); 111 | case P2P_PING: 112 | return new MyHPingMessage(packed); 113 | case P2P_PONG: 114 | return new MyHPongMessage(packed); 115 | case TRX: 116 | return new MyHTransactionMessage(packed); 117 | case BLOCK: 118 | return new MyHBlockMessage(packed); 119 | case TRXS: 120 | return new MyHTransactionsMessage(packed); 121 | case INVENTORY: 122 | return new MyHInventoryMessage(packed); 123 | case FETCH_INV_DATA: 124 | return new MyHFetchInvDataMessageMyH(packed); 125 | case SYNC_BLOCK_CHAIN: 126 | return new MyHSyncBlockChainMessage(packed); 127 | case BLOCK_CHAIN_INVENTORY: 128 | return new MyHChainInventoryMessage(packed); 129 | case PBFT_COMMIT_MSG: 130 | return new MyHPbftCommitMessage(packed); 131 | default: 132 | throw new P2pException(P2pException.TypeEnum.NO_SUCH_MESSAGE, 133 | receivedTypes.toString() + DATA_LEN + packed.length); 134 | } 135 | } 136 | 137 | public static ByteString base64ToByteString(String base64String) { 138 | // Step 1: 去除前导 0 139 | // 假设前导0是字符 '0' 140 | base64String = base64String.replaceFirst("^0+", ""); 141 | 142 | // Step 2: Base64 解码 143 | byte[] decodedBytes = Base64.getDecoder().decode(base64String); 144 | 145 | // Step 3: 创建 ByteString 对象 146 | return ByteString.copyFrom(decodedBytes); 147 | } 148 | public static byte[] hexStringToByteArray(String s) { 149 | int len = s.length(); 150 | byte[] data = new byte[len / 2]; 151 | for (int i = 0; i < len; i += 2) { 152 | data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4) 153 | + Character.digit(s.charAt(i+1), 16)); 154 | } 155 | return data; 156 | } 157 | public static byte[] generateRandomNodeId() { 158 | // 1. 创建一个 64 字节的随机字节数组 159 | byte[] randomBytes = new byte[64]; 160 | SecureRandom random = new SecureRandom(); 161 | random.nextBytes(randomBytes); // 生成随机字节 162 | 163 | return randomBytes; 164 | } 165 | 166 | 167 | } 168 | 169 | -------------------------------------------------------------------------------- /src/myConnection/MyChannel.java: -------------------------------------------------------------------------------- 1 | package myConnection; 2 | 3 | import com.google.common.base.Throwables; 4 | import myConnection.higher.MyHMessage.MyHHelloMessage; 5 | import myConnection.message.MyHelloMessage; 6 | import myConnection.message.MyMessage; 7 | import myConnection.socket.MyMessageHandler; 8 | import myConnection.socket.MyP2pProtobufVariant32FrameDecoder; 9 | import io.netty.buffer.ByteBuf; 10 | import io.netty.buffer.Unpooled; 11 | import io.netty.channel.ChannelFutureListener; 12 | import io.netty.channel.ChannelHandlerContext; 13 | import io.netty.channel.ChannelPipeline; 14 | import io.netty.handler.codec.CorruptedFrameException; 15 | import io.netty.handler.codec.protobuf.ProtobufVarint32LengthFieldPrepender; 16 | import io.netty.handler.timeout.ReadTimeoutException; 17 | import io.netty.handler.timeout.ReadTimeoutHandler; 18 | import lombok.Getter; 19 | import lombok.Setter; 20 | import lombok.extern.slf4j.Slf4j; 21 | import org.apache.commons.lang3.StringUtils; 22 | import org.tron.p2p.connection.ChannelManager; 23 | import org.tron.p2p.connection.business.upgrade.UpgradeController; 24 | import org.tron.p2p.discover.Node; 25 | import org.tron.p2p.exception.P2pException; 26 | import org.tron.p2p.stats.TrafficStats; 27 | import org.tron.p2p.utils.ByteArray; 28 | 29 | import java.io.IOException; 30 | import java.net.InetAddress; 31 | import java.net.InetSocketAddress; 32 | import java.net.SocketAddress; 33 | import java.util.Objects; 34 | import java.util.concurrent.TimeUnit; 35 | 36 | @Slf4j(topic = "net") 37 | public class MyChannel { 38 | public volatile boolean waitForPong = false; 39 | public volatile long pingSent = System.currentTimeMillis(); 40 | 41 | @Getter 42 | private MyHelloMessage helloMessage; 43 | @Setter 44 | @Getter 45 | public MyHHelloMessage hHelloMessage; 46 | @Getter 47 | private Node node; 48 | @Getter 49 | private int version; 50 | @Getter 51 | private ChannelHandlerContext ctx; 52 | @Getter 53 | private InetSocketAddress inetSocketAddress; 54 | @Getter 55 | private InetAddress inetAddress; 56 | @Getter 57 | private volatile long disconnectTime; 58 | @Getter 59 | @Setter 60 | private volatile boolean isDisconnect = false; 61 | @Getter 62 | @Setter 63 | private long lastSendTime = System.currentTimeMillis(); 64 | @Getter 65 | private final long startTime = System.currentTimeMillis(); 66 | @Getter 67 | private boolean isActive = false; 68 | @Getter 69 | private boolean isTrustPeer; 70 | @Getter 71 | @Setter 72 | private volatile boolean finishHandshake; 73 | @Getter 74 | @Setter 75 | private String nodeId; 76 | @Setter 77 | @Getter 78 | private boolean discoveryMode; 79 | @Getter 80 | private long avgLatency; 81 | private long count; 82 | 83 | public void init(ChannelPipeline pipeline, String nodeId, boolean discoveryMode) { 84 | this.discoveryMode = discoveryMode; 85 | this.nodeId = nodeId; 86 | this.isActive = StringUtils.isNotEmpty(nodeId); 87 | MyMessageHandler messageHandler = new MyMessageHandler(this); 88 | pipeline.addLast("readTimeoutHandler", new ReadTimeoutHandler(60, TimeUnit.SECONDS)); 89 | pipeline.addLast(TrafficStats.tcp); 90 | pipeline.addLast("protoPrepend", new ProtobufVarint32LengthFieldPrepender()); 91 | pipeline.addLast("protoDecode", new MyP2pProtobufVariant32FrameDecoder(this)); 92 | pipeline.addLast("messageHandler", messageHandler); 93 | } 94 | 95 | public void processException(Throwable throwable) { 96 | Throwable baseThrowable = throwable; 97 | try { 98 | baseThrowable = Throwables.getRootCause(baseThrowable); 99 | } catch (IllegalArgumentException e) { 100 | baseThrowable = e.getCause(); 101 | log.warn("Loop in causal chain detected"); 102 | } 103 | SocketAddress address = ctx.channel().remoteAddress(); 104 | if (throwable instanceof ReadTimeoutException 105 | || throwable instanceof IOException 106 | || throwable instanceof CorruptedFrameException) { 107 | log.warn("Close peer {}, reason: {}", address, throwable.getMessage()); 108 | } else if (baseThrowable instanceof P2pException) { 109 | log.warn("Close peer {}, type: ({}), info: {}", 110 | address, ((P2pException) baseThrowable).getType(), baseThrowable.getMessage()); 111 | } else { 112 | log.error("Close peer {}, exception caught", address, throwable); 113 | } 114 | close(); 115 | } 116 | 117 | public void setHelloMessage(MyHelloMessage helloMessage) { 118 | this.helloMessage = helloMessage; 119 | this.node = helloMessage.getFrom(); 120 | this.nodeId = node.getHexId(); //update node id from handshake 121 | this.version = helloMessage.getVersion(); 122 | } 123 | 124 | public void setChannelHandlerContext(ChannelHandlerContext ctx) { 125 | this.ctx = ctx; 126 | this.inetSocketAddress = (InetSocketAddress) ctx.channel().remoteAddress(); 127 | this.inetAddress = inetSocketAddress.getAddress(); 128 | this.isTrustPeer =false; 129 | } 130 | 131 | public void close(long banTime) { 132 | this.isDisconnect = true; 133 | this.disconnectTime = System.currentTimeMillis(); 134 | ChannelManager.banNode(this.inetAddress, banTime); 135 | ctx.close(); 136 | } 137 | 138 | public void close() { 139 | close(1L); 140 | } 141 | 142 | public void send(MyMessage message) { 143 | if (message.needToLog()) { 144 | log.info("Send message to channel {}, {}", inetSocketAddress, message); 145 | } else { 146 | log.debug("Send message to channel {}, {}", inetSocketAddress, message); 147 | } 148 | send(message.getSendData()); 149 | } 150 | 151 | public void send(byte[] data) { 152 | try { 153 | byte type = data[0]; 154 | if (isDisconnect) { 155 | log.warn("Send to {} failed as channel has closed, message-type:{} ", 156 | ctx.channel().remoteAddress(), type); 157 | return; 158 | } 159 | 160 | if (finishHandshake) { 161 | data = UpgradeController.codeSendData(version, data); 162 | } 163 | 164 | ByteBuf byteBuf = Unpooled.wrappedBuffer(data); 165 | ctx.writeAndFlush(byteBuf).addListener((ChannelFutureListener) future -> { 166 | if (!future.isSuccess() && !isDisconnect) { 167 | log.warn("Send to {} failed, message-type:{}, cause:{}", 168 | ctx.channel().remoteAddress(), ByteArray.byte2int(type), 169 | future.cause().getMessage()); 170 | } 171 | }); 172 | setLastSendTime(System.currentTimeMillis()); 173 | } catch (Exception e) { 174 | log.warn("Send message to {} failed, {}", inetSocketAddress, e.getMessage()); 175 | ctx.channel().close(); 176 | } 177 | } 178 | 179 | public void updateAvgLatency(long latency) { 180 | long total = this.avgLatency * this.count; 181 | this.count++; 182 | this.avgLatency = (total + latency) / this.count; 183 | } 184 | 185 | @Override 186 | public boolean equals(Object o) { 187 | if (this == o) { 188 | return true; 189 | } 190 | if (o == null || getClass() != o.getClass()) { 191 | return false; 192 | } 193 | MyChannel channel = (MyChannel) o; 194 | return Objects.equals(inetSocketAddress, channel.inetSocketAddress); 195 | } 196 | 197 | @Override 198 | public int hashCode() { 199 | return inetSocketAddress.hashCode(); 200 | } 201 | 202 | @Override 203 | public String toString() { 204 | return String.format("%s | %s", inetSocketAddress, 205 | StringUtils.isEmpty(nodeId) ? "" : nodeId); 206 | } 207 | } 208 | -------------------------------------------------------------------------------- /src/myConnection/higher/MyHMessage/MyHHelloMessage.java: -------------------------------------------------------------------------------- 1 | package myConnection.higher.MyHMessage; 2 | 3 | import myDiscover.MyConfig; 4 | import com.google.protobuf.ByteString; 5 | import lombok.Getter; 6 | import myDiscover.Tool; 7 | import org.apache.commons.lang3.StringUtils; 8 | import org.tron.common.utils.StringUtil; 9 | import org.tron.core.capsule.BlockCapsule; 10 | import org.tron.core.net.message.MessageTypes; 11 | import org.tron.p2p.discover.Node; 12 | import org.tron.p2p.utils.ByteArray; 13 | import org.tron.protos.Discover.Endpoint; 14 | import org.tron.protos.Protocol; 15 | import org.tron.protos.Protocol.HelloMessage.Builder; 16 | 17 | @Getter 18 | public class MyHHelloMessage extends MyTronMessage{ 19 | private Protocol.HelloMessage helloMessage; 20 | 21 | public MyHHelloMessage(byte type, byte[] rawData) throws Exception { 22 | super(type, rawData); 23 | this.helloMessage = Protocol.HelloMessage.parseFrom(rawData); 24 | } 25 | 26 | public MyHHelloMessage(byte[] data) throws Exception { 27 | super(MessageTypes.P2P_HELLO.asByte(), data); 28 | this.helloMessage = Protocol.HelloMessage.parseFrom(data); 29 | } 30 | public MyHHelloMessage(){ 31 | Endpoint from = MyConfig.getHomeFrom(); 32 | MyConfig.MyBlockId MyHeadBlockId = MyConfig.getHeadBlockId(); 33 | Protocol.HelloMessage.BlockId hBlockId = Protocol.HelloMessage.BlockId.newBuilder() 34 | .setHash(MyHeadBlockId.getByteString()) 35 | .setNumber(MyHeadBlockId.getNum()) 36 | .build(); 37 | byte[] genesisBytes = Tool.hexStringToByteArray(MyConfig.getGenesisHashHexString()); 38 | MyConfig.MyBlockId genesisBlockId = new MyConfig.MyBlockId(genesisBytes,0); 39 | Protocol.HelloMessage.BlockId gBlockId = Protocol.HelloMessage.BlockId.newBuilder() 40 | .setHash(genesisBlockId.getByteString()) 41 | .setNumber(0) 42 | .build(); 43 | Builder builder = Protocol.HelloMessage.newBuilder(); 44 | builder.setFrom(from); 45 | builder.setVersion(MyConfig.getNetwork()); 46 | builder.setTimestamp(System.currentTimeMillis()); 47 | builder.setGenesisBlockId(gBlockId); 48 | builder.setSolidBlockId(hBlockId); 49 | builder.setHeadBlockId(hBlockId); 50 | builder.setNodeType(0);//Full node 51 | builder.setLowestBlockNum(0); 52 | builder.setCodeVersion(ByteString.copyFrom(MyConfig.getCodeVersion().getBytes())); 53 | 54 | this.helloMessage = builder.build(); 55 | this.type = MessageTypes.P2P_HELLO.asByte(); 56 | this.data = this.helloMessage.toByteArray(); 57 | } 58 | // public MyHHelloMessage(Node from, long timestamp) { 59 | // 60 | // Endpoint fromEndpoint = getEndpointFromNode(from); 61 | // 62 | // BlockCapsule.BlockId gid = chainBaseManager.getGenesisBlockId(); 63 | // Protocol.HelloMessage.BlockId gBlockId = Protocol.HelloMessage.BlockId.newBuilder() 64 | // .setHash(gid.getByteString()) 65 | // .setNumber(gid.getNum()) 66 | // .build(); 67 | // 68 | // BlockCapsule.BlockId sid = chainBaseManager.getSolidBlockId(); 69 | // Protocol.HelloMessage.BlockId sBlockId = Protocol.HelloMessage.BlockId.newBuilder() 70 | // .setHash(sid.getByteString()) 71 | // .setNumber(sid.getNum()) 72 | // .build(); 73 | // 74 | // BlockCapsule.BlockId hid = chainBaseManager.getHeadBlockId(); 75 | // Protocol.HelloMessage.BlockId hBlockId = Protocol.HelloMessage.BlockId.newBuilder() 76 | // .setHash(hid.getByteString()) 77 | // .setNumber(hid.getNum()) 78 | // .build(); 79 | // Builder builder = Protocol.HelloMessage.newBuilder(); 80 | // builder.setFrom(fromEndpoint); 81 | // builder.setVersion(MyConfig.getNetwork()); 82 | // builder.setTimestamp(timestamp); 83 | // builder.setGenesisBlockId(gBlockId); 84 | // builder.setSolidBlockId(sBlockId); 85 | // builder.setHeadBlockId(hBlockId); 86 | // builder.setNodeType(chainBaseManager.getNodeType().getType()); 87 | // builder.setLowestBlockNum(chainBaseManager.isLiteNode() 88 | // ? chainBaseManager.getLowestBlockNum() : 0); 89 | // builder.setCodeVersion(ByteString.copyFrom(MyConfig.getCodeVersion().getBytes())); 90 | // 91 | // this.helloMessage = builder.build(); 92 | // this.type = MessageTypes.P2P_HELLO.asByte(); 93 | // this.data = this.helloMessage.toByteArray(); 94 | // } 95 | 96 | public void setHelloMessage(Protocol.HelloMessage helloMessage) { 97 | this.helloMessage = helloMessage; 98 | this.data = this.helloMessage.toByteArray(); 99 | } 100 | 101 | public int getVersion() { 102 | return this.helloMessage.getVersion(); 103 | } 104 | 105 | public int getNodeType() { 106 | return this.helloMessage.getNodeType(); 107 | } 108 | 109 | public long getLowestBlockNum() { 110 | return this.helloMessage.getLowestBlockNum(); 111 | } 112 | 113 | public long getTimestamp() { 114 | return this.helloMessage.getTimestamp(); 115 | } 116 | 117 | public Node getFrom() { 118 | Endpoint from = this.helloMessage.getFrom(); 119 | return new Node(from.getNodeId().toByteArray(), 120 | ByteArray.toStr(from.getAddress().toByteArray()), 121 | ByteArray.toStr(from.getAddressIpv6().toByteArray()), from.getPort()); 122 | } 123 | 124 | public BlockCapsule.BlockId getGenesisBlockId() { 125 | return new BlockCapsule.BlockId(this.helloMessage.getGenesisBlockId().getHash(), 126 | this.helloMessage.getGenesisBlockId().getNumber()); 127 | } 128 | 129 | public BlockCapsule.BlockId getSolidBlockId() { 130 | return new BlockCapsule.BlockId(this.helloMessage.getSolidBlockId().getHash(), 131 | this.helloMessage.getSolidBlockId().getNumber()); 132 | } 133 | 134 | public BlockCapsule.BlockId getHeadBlockId() { 135 | return new BlockCapsule.BlockId(this.helloMessage.getHeadBlockId().getHash(), 136 | this.helloMessage.getHeadBlockId().getNumber()); 137 | } 138 | 139 | @Override 140 | public Class getAnswerMessage() { 141 | return null; 142 | } 143 | 144 | @Override 145 | public String toString() { 146 | StringBuilder builder = new StringBuilder(); 147 | 148 | builder.append(super.toString()) 149 | .append("from: ").append(getFrom().getInetSocketAddressV4()).append("\n") 150 | .append("timestamp: ").append(getTimestamp()).append("\n") 151 | .append("headBlockId: ").append(getHeadBlockId().getString()).append("\n") 152 | .append("nodeType: ").append(helloMessage.getNodeType()).append("\n") 153 | .append("lowestBlockNum: ").append(helloMessage.getLowestBlockNum()).append("\n"); 154 | 155 | ByteString address = helloMessage.getAddress(); 156 | if (!address.isEmpty()) { 157 | builder.append("address:") 158 | .append(StringUtil.encode58Check(address.toByteArray())).append("\n"); 159 | } 160 | 161 | ByteString signature = helloMessage.getSignature(); 162 | if (!signature.isEmpty()) { 163 | builder.append("signature:") 164 | .append(signature.toByteArray().length).append("\n"); 165 | } 166 | 167 | ByteString codeVersion = helloMessage.getCodeVersion(); 168 | if (!codeVersion.isEmpty()) { 169 | builder.append("codeVersion:") 170 | .append(new String(codeVersion.toByteArray())).append("\n"); 171 | } 172 | 173 | return builder.toString(); 174 | } 175 | 176 | public Protocol.HelloMessage getInstance() { 177 | return this.helloMessage; 178 | } 179 | 180 | public boolean valid() { 181 | byte[] genesisBlockByte = this.helloMessage.getGenesisBlockId().getHash().toByteArray(); 182 | if (genesisBlockByte.length == 0) { 183 | return false; 184 | } 185 | 186 | byte[] solidBlockId = this.helloMessage.getSolidBlockId().getHash().toByteArray(); 187 | if (solidBlockId.length == 0) { 188 | return false; 189 | } 190 | 191 | byte[] headBlockId = this.helloMessage.getHeadBlockId().getHash().toByteArray(); 192 | if (headBlockId.length == 0) { 193 | return false; 194 | } 195 | 196 | int maxByteSize = 200; 197 | ByteString address = this.helloMessage.getAddress(); 198 | if (!address.isEmpty() && address.toByteArray().length > maxByteSize) { 199 | return false; 200 | } 201 | 202 | ByteString sig = this.helloMessage.getSignature(); 203 | if (!sig.isEmpty() && sig.toByteArray().length > maxByteSize) { 204 | return false; 205 | } 206 | 207 | ByteString codeVersion = this.helloMessage.getCodeVersion(); 208 | if (!codeVersion.isEmpty() && codeVersion.toByteArray().length > maxByteSize) { 209 | return false; 210 | } 211 | 212 | return true; 213 | } 214 | 215 | public static Endpoint getEndpointFromNode(Node node) { 216 | Endpoint.Builder builder = Endpoint.newBuilder() 217 | .setPort(node.getPort()); 218 | if (node.getId() != null) { 219 | builder.setNodeId(ByteString.copyFrom(node.getId())); 220 | } 221 | if (StringUtils.isNotEmpty(node.getHostV4())) { 222 | builder.setAddress( 223 | ByteString.copyFrom(org.tron.p2p.utils.ByteArray.fromString(node.getHostV4()))); 224 | } 225 | if (StringUtils.isNotEmpty(node.getHostV6())) { 226 | builder.setAddressIpv6( 227 | ByteString.copyFrom(org.tron.p2p.utils.ByteArray.fromString(node.getHostV6()))); 228 | } 229 | return builder.build(); 230 | } 231 | } 232 | -------------------------------------------------------------------------------- /src/myConnection/MyChannelManager.java: -------------------------------------------------------------------------------- 1 | package myConnection; 2 | 3 | import io.netty.channel.ChannelFuture; 4 | import io.netty.channel.ChannelFutureListener; 5 | import lombok.Getter; 6 | import lombok.extern.slf4j.Slf4j; 7 | import myConnection.handshake.MyHandshakeService; 8 | import myConnection.keepalive.MyKeepAliveService; 9 | import myConnection.message.MyMessage; 10 | import myConnection.message.MyP2pDisconnectMessage; 11 | import myConnection.socket.MyPeerClient; 12 | import myConnection.socket.MyPeerServer; 13 | import myDiscover.MyConfig; 14 | import myDiscover.Tool; 15 | import org.tron.p2p.connection.business.handshake.DisconnectCode; 16 | import org.tron.p2p.discover.Node; 17 | import org.tron.p2p.exception.P2pException; 18 | import org.tron.p2p.protos.Connect; 19 | import org.tron.p2p.utils.ByteArray; 20 | 21 | import java.net.InetAddress; 22 | import java.net.InetSocketAddress; 23 | import java.util.ArrayList; 24 | import java.util.List; 25 | import java.util.Map; 26 | import java.util.concurrent.ConcurrentHashMap; 27 | 28 | @Slf4j 29 | public class MyChannelManager { 30 | 31 | @Getter 32 | private static MyHandshakeService handshakeService; 33 | @Getter 34 | private static MyPeerClient peerClient; 35 | 36 | private static MyPeerServer peerServer; 37 | 38 | private static MyKeepAliveService keepAliveService; 39 | 40 | private static MyNodeDetectService nodeDetectService; 41 | 42 | @Getter 43 | private static final Map channels = new ConcurrentHashMap<>(); 44 | 45 | private static boolean isInit = false; 46 | 47 | public static volatile boolean isShutdown = false; 48 | 49 | 50 | public static void main(String[] args) { 51 | MyChannelManager.init(); 52 | String localIdString; 53 | String remoteIp; 54 | byte[] randomId = Tool.generateRandomNodeId(); 55 | MyConfig.init(randomId); 56 | for (int i = 0; i < args.length; i++) { 57 | if ("--localId".equals(args[i])) { 58 | if (i + 1 < args.length) { // 确保端口值存在 59 | try { 60 | localIdString = args[i + 1]; 61 | MyConfig.init(localIdString); 62 | } catch (NumberFormatException e) { 63 | System.err.println("Invalid id: " + args[i + 1]); 64 | System.exit(1); 65 | } 66 | } 67 | } 68 | if("--remoteIp".equals(args[i])) { 69 | if (i + 1 < args.length) { // 确保端口值存在 70 | try { 71 | remoteIp = args[i + 1]; 72 | MyConfig.setToIp(remoteIp); 73 | 74 | } catch (NumberFormatException e) { 75 | System.err.println("Invalid ip: " + args[i + 1]); 76 | System.exit(1); 77 | } 78 | } 79 | } 80 | } 81 | 82 | ChannelFuture channelFuture = peerClient.connectAsync(MyConfig.getTo(), false); 83 | // if (channelFuture != null) { 84 | // // 监控 Channel 的关闭事件 85 | // 86 | // } 87 | } 88 | 89 | public static void init(){ 90 | isInit=true; 91 | handshakeService=new MyHandshakeService(); 92 | peerClient = new MyPeerClient(); 93 | peerServer = new MyPeerServer(); 94 | keepAliveService = new MyKeepAliveService(); 95 | //peerServer.init(); 96 | peerClient.init(); 97 | keepAliveService.init(); 98 | 99 | } 100 | 101 | public static void connect(InetSocketAddress address) { 102 | peerClient.connect(address.getAddress().getHostAddress(), address.getPort(), 103 | ByteArray.toHexString(MyConfig.getLocalId())); 104 | } 105 | 106 | public static ChannelFuture connect(Node node, ChannelFutureListener future) { 107 | return peerClient.connect(node, future); 108 | } 109 | public static void notifyDisconnect(MyChannel channel) { 110 | if (channel.getInetSocketAddress() == null) { 111 | //log.warn("Notify Disconnect peer has no address."); 112 | return; 113 | } 114 | channels.remove(channel.getInetSocketAddress()); 115 | MyConfig.handlerList.forEach(h -> h.onDisconnect(channel)); 116 | InetAddress inetAddress = channel.getInetAddress(); 117 | //if (inetAddress != null) { 118 | //banNode(inetAddress, Parameter.DEFAULT_BAN_TIME); 119 | //} 120 | } 121 | public static synchronized DisconnectCode processPeer(MyChannel channel) { 122 | 123 | // if (!channel.isActive() && !channel.isTrustPeer()) { 124 | // InetAddress inetAddress = channel.getInetAddress(); 125 | // if (bannedNodes.getIfPresent(inetAddress) != null 126 | // && bannedNodes.getIfPresent(inetAddress) > System.currentTimeMillis()) { 127 | // log.info("Peer {} recently disconnected", channel); 128 | // return DisconnectCode.TIME_BANNED; 129 | // } 130 | // 131 | // if (channels.size() >= Parameter.p2pConfig.getMaxConnections()) { 132 | // log.info("Too many peers, disconnected with {}", channel); 133 | // return DisconnectCode.TOO_MANY_PEERS; 134 | // } 135 | // 136 | // int num = getConnectionNum(channel.getInetAddress()); 137 | // if (num >= Parameter.p2pConfig.getMaxConnectionsWithSameIp()) { 138 | // log.info("Max connection with same ip {}", channel); 139 | // return DisconnectCode.MAX_CONNECTION_WITH_SAME_IP; 140 | // } 141 | // } 142 | 143 | // if (StringUtils.isNotEmpty(channel.getNodeId())) { 144 | // for (Channel c : channels.values()) { 145 | // if (channel.getNodeId().equals(c.getNodeId())) { 146 | // if (c.getStartTime() > channel.getStartTime()) { 147 | // //c.close(); 148 | // } else { 149 | // //log.info("Duplicate peer {}, exist peer {}", channel, c); 150 | // return DisconnectCode.DUPLICATE_PEER; 151 | // } 152 | // } 153 | // } 154 | // } 155 | 156 | channels.put(channel.getInetSocketAddress(), channel); 157 | 158 | //log.info("Add peer {}, total channels: {}", channel.getInetSocketAddress(), channels.size()); 159 | return DisconnectCode.NORMAL; 160 | } 161 | public static void close() { 162 | if (!isInit || isShutdown) { 163 | return; 164 | } 165 | isShutdown = true; 166 | //connPoolService.close(); 167 | keepAliveService.close(); 168 | peerServer.close(); 169 | peerClient.close(); 170 | //nodeDetectService.close(); 171 | } 172 | public static void processMessage(MyChannel channel, byte[] data) throws P2pException { 173 | if (data == null || data.length == 0) { 174 | throw new P2pException(P2pException.TypeEnum.EMPTY_MESSAGE, ""); 175 | } 176 | if (data[0] >= 0) { 177 | handMessage(channel, data); 178 | return; 179 | } 180 | 181 | MyMessage message = MyMessage.parse(data); 182 | 183 | System.out.println("receive msg from channel "+channel.getInetSocketAddress()+"type: "+message); 184 | // if (message.needToLog()) { 185 | // //log.info("Receive message from channel: {}, {}", channel.getInetSocketAddress(), message); 186 | // } else { 187 | // //log.debug("Receive message from channel {}, {}", channel.getInetSocketAddress(), message); 188 | // } 189 | 190 | switch (message.getType()) { 191 | case KEEP_ALIVE_PING: 192 | 193 | log.info("received KEEP_ALIVE_PING from {}",channel.getInetSocketAddress()); 194 | keepAliveService.processMessage(channel, message); 195 | break; 196 | case KEEP_ALIVE_PONG: 197 | log.info("received KEEP_ALIVE_PONG from {}",channel.getInetSocketAddress()); 198 | keepAliveService.processMessage(channel, message); 199 | break; 200 | case HANDSHAKE_HELLO: 201 | log.info("received HANDSHAKE_HELLO from {}",channel.getInetSocketAddress()); 202 | handshakeService.processMessage(channel, message); 203 | break; 204 | case STATUS: 205 | log.info("received STATUS from {}",channel.getInetSocketAddress()); 206 | //nodeDetectService.processMessage(channel, message); 207 | break; 208 | case DISCONNECT: 209 | log.info("received DISCONNECT from {}",channel.getInetSocketAddress()); 210 | channel.close(); 211 | break; 212 | default: 213 | throw new P2pException(P2pException.TypeEnum.NO_SUCH_MESSAGE, "type:" + data[0]); 214 | } 215 | } 216 | private static void handMessage(MyChannel channel, byte[] data) throws P2pException { 217 | 218 | if (channel.isDiscoveryMode()) { 219 | channel.send(new MyP2pDisconnectMessage(Connect.DisconnectReason.DISCOVER_MODE)); 220 | channel.getCtx().close(); 221 | return; 222 | } 223 | 224 | if (!channel.isFinishHandshake()) { 225 | channel.setFinishHandshake(true); 226 | DisconnectCode code = processPeer(channel); 227 | if (!DisconnectCode.NORMAL.equals(code)) { 228 | Connect.DisconnectReason disconnectReason = getDisconnectReason(code); 229 | channel.send(new MyP2pDisconnectMessage(disconnectReason)); 230 | channel.getCtx().close(); 231 | return; 232 | } 233 | MyConfig.hp2pEventHandler.onConnect(channel); 234 | } 235 | 236 | MyConfig.hp2pEventHandler.onMessage(channel, data); 237 | } 238 | public static Connect.DisconnectReason getDisconnectReason(DisconnectCode code) { 239 | Connect.DisconnectReason disconnectReason; 240 | switch (code) { 241 | case DIFFERENT_VERSION: 242 | disconnectReason = Connect.DisconnectReason.DIFFERENT_VERSION; 243 | break; 244 | case TIME_BANNED: 245 | disconnectReason = Connect.DisconnectReason.RECENT_DISCONNECT; 246 | break; 247 | case DUPLICATE_PEER: 248 | disconnectReason = Connect.DisconnectReason.DUPLICATE_PEER; 249 | break; 250 | case TOO_MANY_PEERS: 251 | disconnectReason = Connect.DisconnectReason.TOO_MANY_PEERS; 252 | break; 253 | case MAX_CONNECTION_WITH_SAME_IP: 254 | disconnectReason = Connect.DisconnectReason.TOO_MANY_PEERS_WITH_SAME_IP; 255 | break; 256 | default: { 257 | disconnectReason = Connect.DisconnectReason.UNKNOWN; 258 | } 259 | } 260 | return disconnectReason; 261 | } 262 | public static synchronized void updateNodeId(MyChannel channel, String nodeId) { 263 | channel.setNodeId(nodeId); 264 | // if (nodeId.equals(Hex.toHexString(MyConfig.getLocalId()))) { 265 | // //log.warn("Channel {} is myself", channel.getInetSocketAddress()); 266 | // channel.send(new MyP2pDisconnectMessage(Connect.DisconnectReason.DUPLICATE_PEER)); 267 | // channel.close(); 268 | // return; 269 | // } 270 | 271 | List list = new ArrayList<>(); 272 | channels.values().forEach(c -> { 273 | if (nodeId.equals(c.getNodeId())) { 274 | list.add(c); 275 | } 276 | }); 277 | if (list.size() <= 1) { 278 | return; 279 | } 280 | 281 | } 282 | 283 | // public static void triggerConnect(InetSocketAddress address) { 284 | // connPoolService.triggerConnect(address); 285 | // } 286 | public static void logDisconnectReason(MyChannel channel, Connect.DisconnectReason reason) { 287 | log.info("Try to close channel: {}, reason: {}", channel.getInetSocketAddress(), reason.name()); 288 | } 289 | 290 | 291 | } 292 | -------------------------------------------------------------------------------- /src/myDiscover/MyConfig.java: -------------------------------------------------------------------------------- 1 | package myDiscover; 2 | 3 | import com.google.common.primitives.Longs; 4 | import com.google.protobuf.ByteString; 5 | import lombok.Getter; 6 | import lombok.Setter; 7 | import myConnection.MyHP2pEventHandlerImpl; 8 | import myConnection.MyP2pEventHandler; 9 | import myConnection.higher.MyHMessage.MyHHelloMessage; 10 | import org.apache.commons.lang3.StringUtils; 11 | import org.json.JSONArray; 12 | import org.json.JSONObject; 13 | import org.tron.common.utils.Sha256Hash; 14 | import org.tron.core.capsule.BlockCapsule; 15 | import org.tron.p2p.discover.Node; 16 | import org.tron.p2p.exception.P2pException; 17 | import org.tron.p2p.protos.Discover; 18 | import org.tron.p2p.utils.ByteArray; 19 | import org.tron.p2p.utils.NetUtil; 20 | 21 | import java.io.BufferedReader; 22 | import java.io.IOException; 23 | import java.io.InputStreamReader; 24 | import java.net.HttpURLConnection; 25 | import java.net.URL; 26 | import java.util.*; 27 | public class MyConfig { 28 | @Getter 29 | private static Node from; 30 | @Getter 31 | private static Node to; 32 | @Getter 33 | private static byte[] id ={-49, -117, 20, 19, -71, 85, -16, 57, 5, -59, -22, -79, -103, -118, -12, 54, 92, -77, 13, 71, 35, 75, 41, -91, -101, -38, -76, -47, -106, 116, -1, 7, -43, 23, -63, 27, 122, 107, -67, 127, -44, 67, 79, 43, 55, 117, -46, 18, 118, 5, 17, 39, -90, 52, 50, 12, 62, 11, 47, 29, -67, -75, 68, -15}; 34 | @Getter@Setter 35 | private static byte[] localId ={-49, -117, 20, 19, -71, 85, -16, 57, 5, -59, -22, -79, -103, -118, -12, 54, 92, -77, 13, 71, 35, 75, 41, -91, -101, -38, -76, -47, -106, 116, -1, 7, -43, 23, -63, 27, 122, 107, -67, 127, -44, 67, 79, 43, 55, 117, -46, 18, 118, 5, 17, 39, -90, 52, 50, 12, 62, 11, 47, 29, -67, -75, 68, -14}; 36 | @Getter 37 | private static String localIp= NetUtil.getExternalIpV4(); 38 | @Getter 39 | private static int fromPort=18899; 40 | @Getter 41 | private static int toPort=18888; 42 | @Getter 43 | 44 | private static String toIp="填入IP"; 45 | 46 | @Getter 47 | private static int network=11111; 48 | @Getter 49 | private static String GenesisHashHexString="00000000000000001ebf88508a03865c71d452e25f4d51194196a1d22b6653dc"; 50 | public static volatile List handlerList = new ArrayList<>(); 51 | public static volatile Map handlerMap = new HashMap<>(); 52 | 53 | public static int version = 1; 54 | 55 | public static final int TCP_NETTY_WORK_THREAD_NUM = 0; 56 | 57 | public static final int UDP_NETTY_WORK_THREAD_NUM = 1; 58 | 59 | public static final int NODE_CONNECTION_TIMEOUT = 2000; 60 | 61 | public static final int KEEP_ALIVE_TIMEOUT = 2_000_000_000; 62 | 63 | public static final int PING_TIMEOUT = 20_000; 64 | 65 | public static final int NETWORK_TIME_DIFF = 1000; 66 | 67 | public static final long DEFAULT_BAN_TIME = 60_000; 68 | 69 | public static final int MAX_MESSAGE_LENGTH = 5 * 1024 * 1024; 70 | @Getter 71 | public static final String codeVersion = "4.7.6"; 72 | public static final String VERSION_NAME = "GreatVoyage-v4.7.4-44-g8720e06a6"; 73 | public static final String VERSION_CODE = "18306"; 74 | public static MyHP2pEventHandlerImpl hp2pEventHandler; 75 | 76 | @Setter 77 | @Getter 78 | public static MyHHelloMessage helloMessageReceive; 79 | 80 | @Setter 81 | @Getter 82 | public static MyHHelloMessage helloMessageSend; 83 | // public static final MyBlockId genesisBlockId=; 84 | // public static MyBlockId solidBlockId=; 85 | // public static MyBlockId headBlockId = ; 86 | private long timestamp; 87 | public MyConfig(){ 88 | 89 | } 90 | public static void test(){ 91 | System.out.println("localId: "+Tool.encodeToBase64(localId)); 92 | } 93 | public static void init(){ 94 | to = new Node(id,toIp,"",toPort); 95 | from = new Node(localId,localIp,"",fromPort); 96 | System.out.println("localIP: "+localIp); 97 | hp2pEventHandler = new MyHP2pEventHandlerImpl(); 98 | } 99 | public static void init(String localId){ 100 | setLocalId(Tool.decodeFromBase64(localId)); 101 | to = new Node(id,toIp,"",toPort); 102 | from = new Node(Tool.decodeFromBase64(localId),localIp,"",fromPort); 103 | System.out.println("localIP: "+localIp); 104 | System.out.println("localId: "+localId); 105 | hp2pEventHandler = new MyHP2pEventHandlerImpl(); 106 | } 107 | public static void init(byte[] localId){ 108 | setLocalId(localId); 109 | to = new Node(id,toIp,"",toPort); 110 | from = new Node(localId,localIp,"",fromPort); 111 | System.out.println("localIP: "+localIp); 112 | System.out.println("localId: "+ Arrays.toString(localId)); 113 | hp2pEventHandler = new MyHP2pEventHandlerImpl(); 114 | } 115 | public static void setToIp(String toIp){ 116 | to = new Node(id,toIp,"",toPort); 117 | } 118 | public static void addP2pEventHandler(MyP2pEventHandler p2pEventHandler) throws P2pException { 119 | if (p2pEventHandler.getMessageTypes() != null) { 120 | for (Byte type : p2pEventHandler.getMessageTypes()) { 121 | if (handlerMap.get(type) != null) { 122 | throw new P2pException(P2pException.TypeEnum.TYPE_ALREADY_REGISTERED, "type:" + type); 123 | } 124 | } 125 | for (Byte type : p2pEventHandler.getMessageTypes()) { 126 | handlerMap.put(type, p2pEventHandler); 127 | } 128 | } 129 | handlerList.add(p2pEventHandler); 130 | } 131 | public static Discover.Endpoint getHomeNode() { 132 | Discover.Endpoint.Builder builder = Discover.Endpoint.newBuilder() 133 | .setNodeId(ByteString.copyFrom(MyConfig.getLocalId())) 134 | .setPort(MyConfig.getFromPort()); 135 | if (StringUtils.isNotEmpty(MyConfig.getLocalIp())) { 136 | builder.setAddress(ByteString.copyFrom( 137 | ByteArray.fromString(MyConfig.getLocalIp()))); 138 | } 139 | // if (StringUtils.isNotEmpty(Parameter.p2pConfig.getIpv6())) { 140 | // builder.setAddressIpv6(ByteString.copyFrom( 141 | // ByteArray.fromString(Parameter.p2pConfig.getIpv6()))); 142 | // } 143 | return builder.build(); 144 | } 145 | public static class MyBlockId extends Sha256Hash { 146 | 147 | private long num; 148 | 149 | public MyBlockId() { 150 | super(Sha256Hash.ZERO_HASH.getBytes()); 151 | num = 0; 152 | } 153 | 154 | public MyBlockId(Sha256Hash blockId) { 155 | super(blockId.getBytes()); 156 | byte[] blockNum = new byte[8]; 157 | System.arraycopy(blockId.getBytes(), 0, blockNum, 0, 8); 158 | num = Longs.fromByteArray(blockNum); 159 | } 160 | 161 | /** 162 | * Use {@link #wrap(byte[])} instead. 163 | */ 164 | public MyBlockId(Sha256Hash hash, long num) { 165 | super(num, hash); 166 | this.num = num; 167 | } 168 | 169 | public MyBlockId(byte[] hash, long num) { 170 | super(num, hash); 171 | this.num = num; 172 | } 173 | 174 | public MyBlockId(ByteString hash, long num) { 175 | super(num, hash.toByteArray()); 176 | this.num = num; 177 | } 178 | 179 | @Override 180 | public boolean equals(Object o) { 181 | if (this == o) { 182 | return true; 183 | } 184 | if (o == null || (getClass() != o.getClass() && !(o instanceof Sha256Hash))) { 185 | return false; 186 | } 187 | return Arrays.equals(getBytes(), ((Sha256Hash) o).getBytes()); 188 | } 189 | 190 | public String getString() { 191 | return "Num:" + num + ",ID:" + super.toString(); 192 | } 193 | 194 | @Override 195 | public String toString() { 196 | return super.toString(); 197 | } 198 | 199 | @Override 200 | public int hashCode() { 201 | return super.hashCode(); 202 | } 203 | 204 | @Override 205 | public int compareTo(Sha256Hash other) { 206 | if (other.getClass().equals(BlockCapsule.BlockId.class)) { 207 | long otherNum = ((BlockCapsule.BlockId) other).getNum(); 208 | return Long.compare(num, otherNum); 209 | } 210 | return super.compareTo(other); 211 | } 212 | 213 | public long getNum() { 214 | return num; 215 | } 216 | } 217 | public static List getBlockNumberAndHash() { 218 | System.out.println("entering func getBlockNumberAndHash"); 219 | String apiUrl = "https://apilist.tronscanapi.com/api/block?sort=-balance&start=0&limit=1&producer=&number=&start_timestamp=&end_timestamp="; 220 | try { 221 | // Create URL object 222 | BufferedReader in = getBufferedReader(apiUrl); 223 | 224 | // Read the response into a StringBuilder 225 | String inputLine; 226 | StringBuilder response = new StringBuilder(); 227 | while ((inputLine = in.readLine()) != null) { 228 | response.append(inputLine); 229 | } 230 | 231 | // Close the input stream 232 | in.close(); 233 | 234 | // Parse the response JSON 235 | JSONObject jsonResponse = new JSONObject(response.toString()); 236 | JSONArray dataArray = jsonResponse.getJSONArray("data"); 237 | if (!dataArray.isEmpty()) { 238 | JSONObject blockData = dataArray.getJSONObject(0); 239 | long number = blockData.getInt("number"); 240 | String hash = blockData.getString("hash"); 241 | long timestamp = blockData.getInt("timestamp"); 242 | 243 | // Return the extracted values as a formatted string 244 | System.out.println("get res success"); 245 | return Arrays.asList(number,hash,timestamp); 246 | } else { 247 | System.out.println("get res fail, reason: " + response); 248 | 249 | return Arrays.asList(0L,"",0L); 250 | } 251 | 252 | } catch (Exception e) { 253 | System.out.println("get res fail, reason: " + e.getMessage()); 254 | e.printStackTrace(); 255 | return Arrays.asList(0L,"",0L); 256 | } 257 | } 258 | 259 | private static BufferedReader getBufferedReader(String apiUrl) throws IOException { 260 | URL url = new URL(apiUrl); 261 | 262 | // Create HttpURLConnection object 263 | HttpURLConnection connection = (HttpURLConnection) url.openConnection(); 264 | 265 | // Set request method to GET 266 | connection.setRequestMethod("GET"); 267 | connection.setRequestProperty("TRON-PRO-API-KEY", "使用你的api"); 268 | // Get the input stream of the connection 269 | return new BufferedReader(new InputStreamReader(connection.getInputStream())); 270 | } 271 | 272 | public static synchronized MyBlockId getHeadBlockId() { 273 | List res = getBlockNumberAndHash(); 274 | if (res.size() < 3 || res.get(0) == null || res.get(1) == null || res.get(2) == null) { 275 | // 处理 res 为 null 或者 res 的大小小于 3 或者 res 的某个元素为 null 的情况 276 | // 可以抛出异常、记录错误日志或返回一个默认值 277 | System.out.println("res: " + res); 278 | throw new IllegalArgumentException("Invalid block data"); 279 | } 280 | 281 | // 确保 res 中的元素都不为 null 后再进行类型转换 282 | long num; 283 | long timestamp; 284 | String hash; 285 | try { 286 | num = (long) res.get(0); 287 | hash = res.get(1).toString(); 288 | timestamp = (long) res.get(2); 289 | } catch (ClassCastException e) { 290 | // 处理类型转换异常 291 | throw new IllegalArgumentException("Invalid type in block data", e); 292 | } 293 | byte[] hashBytes = Tool.hexStringToByteArray(hash); 294 | //this.timestamp = timestamp; 295 | System.out.println("hash:"+Arrays.toString(hashBytes)); 296 | System.out.println("num"+num); 297 | 298 | return new MyBlockId(hashBytes,num); 299 | 300 | } 301 | public static org.tron.protos.Discover.Endpoint getHomeFrom(){ 302 | org.tron.protos.Discover.Endpoint.Builder builder = org.tron.protos.Discover.Endpoint.newBuilder() 303 | .setPort(fromPort); 304 | builder.setAddress(ByteString.copyFrom(org.tron.p2p.utils.ByteArray.fromString(localIp))); 305 | builder.setNodeId(ByteString.copyFrom(localId)); 306 | return builder.build(); 307 | } 308 | } 309 | 310 | --------------------------------------------------------------------------------