Coverage Summary for Class: MessageVisitor (co.rsk.net.messages)
Class |
Class, %
|
Method, %
|
Line, %
|
MessageVisitor |
0%
(0/1)
|
0%
(0/22)
|
0%
(0/80)
|
1 /*
2 * This file is part of RskJ
3 * Copyright (C) 2019 RSK Labs Ltd.
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU Lesser General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 package co.rsk.net.messages;
20
21 import co.rsk.config.RskSystemProperties;
22 import co.rsk.crypto.Keccak256;
23 import co.rsk.net.*;
24 import co.rsk.scoring.EventType;
25 import co.rsk.scoring.PeerScoringManager;
26 import co.rsk.util.FormatUtils;
27 import org.ethereum.core.Block;
28 import org.ethereum.core.BlockIdentifier;
29 import org.ethereum.core.Transaction;
30 import org.ethereum.net.server.ChannelManager;
31 import org.slf4j.Logger;
32 import org.slf4j.LoggerFactory;
33
34 import java.util.*;
35 import java.util.stream.Collectors;
36
37 /**
38 * The MessageVisitor handles the received wire messages resolution.
39 * <p>
40 * It should only visit a message once per instantiation.
41 */
42 public class MessageVisitor {
43
44 private static final Logger logger = LoggerFactory.getLogger("messagehandler");
45 private static final Logger loggerMessageProcess = LoggerFactory.getLogger("messageProcess");
46
47 private final BlockProcessor blockProcessor;
48 private final SyncProcessor syncProcessor;
49 private final TransactionGateway transactionGateway;
50 private final Peer sender;
51 private final PeerScoringManager peerScoringManager;
52 private final RskSystemProperties config;
53 private final ChannelManager channelManager;
54
55 public MessageVisitor(RskSystemProperties config,
56 BlockProcessor blockProcessor,
57 SyncProcessor syncProcessor,
58 TransactionGateway transactionGateway,
59 PeerScoringManager peerScoringManager,
60 ChannelManager channelManager,
61 Peer sender) {
62
63 this.blockProcessor = blockProcessor;
64 this.syncProcessor = syncProcessor;
65 this.transactionGateway = transactionGateway;
66 this.peerScoringManager = peerScoringManager;
67 this.channelManager = channelManager;
68 this.config = config;
69 this.sender = sender;
70 }
71
72 /**
73 * Processes a BlockMessage message, adding the block to the blockchain if appropriate, or
74 * forwarding it to peers that are missing the Block.
75 *
76 * @param message the BlockMessage.
77 */
78 public void apply(BlockMessage message) {
79 final Block block = message.getBlock();
80
81 logger.trace("Process block {} {}", block.getNumber(), block.getPrintableHash());
82
83 if (block.isGenesis()) {
84 logger.trace("Skip block processing {} {}", block.getNumber(), block.getPrintableHash());
85 return;
86 }
87
88 long blockNumber = block.getNumber();
89
90 if (this.blockProcessor.isAdvancedBlock(blockNumber)) {
91 logger.trace("Too advanced block {} {}", blockNumber, block.getPrintableHash());
92 return;
93 }
94
95 if (blockProcessor.canBeIgnoredForUnclesRewards(block.getNumber())){
96 logger.trace("Block ignored: too far from best block {} {}", blockNumber, block.getPrintableHash());
97 return;
98 }
99
100 if (blockProcessor.hasBlockInSomeBlockchain(block.getHash().getBytes())){
101 logger.trace("Block ignored: it's included in blockchain {} {}", blockNumber, block.getPrintableHash());
102 return;
103 }
104
105 BlockProcessResult result = this.blockProcessor.processBlock(sender, block);
106
107 if (result.isInvalidBlock()) {
108 logger.trace("Invalid block {} {}", blockNumber, block.getPrintableHash());
109 recordEventForPeerScoring(sender, EventType.INVALID_BLOCK);
110 return;
111 }
112
113 tryRelayBlock(block, result);
114
115 sender.imported(result.isBest());
116
117 recordEventForPeerScoring(sender, EventType.VALID_BLOCK);
118 }
119
120 public void apply(StatusMessage message) {
121 final Status status = message.getStatus();
122 logger.trace("Process status {}", status.getBestBlockNumber());
123 this.syncProcessor.processStatus(sender, status);
124 }
125
126 public void apply(GetBlockMessage message) {
127 final byte[] hash = message.getBlockHash();
128 this.blockProcessor.processGetBlock(sender, hash);
129 }
130
131 public void apply(BlockRequestMessage message) {
132 final byte[] hash = message.getBlockHash();
133 this.blockProcessor.processBlockRequest(sender, message.getId(), hash);
134 }
135
136 public void apply(BlockResponseMessage message) {
137 this.syncProcessor.processBlockResponse(sender, message);
138 }
139
140 public void apply(SkeletonRequestMessage message) {
141 final long startNumber = message.getStartNumber();
142 this.blockProcessor.processSkeletonRequest(sender, message.getId(), startNumber);
143 }
144
145 public void apply(BlockHeadersRequestMessage message) {
146 final byte[] hash = message.getHash();
147 final int count = message.getCount();
148 this.blockProcessor.processBlockHeadersRequest(sender, message.getId(), hash, count);
149 }
150
151 public void apply(BlockHashRequestMessage message) {
152 this.blockProcessor.processBlockHashRequest(sender, message.getId(), message.getHeight());
153 }
154
155 public void apply(BlockHashResponseMessage message) {
156 this.syncProcessor.processBlockHashResponse(sender, message);
157 }
158
159 public void apply(NewBlockHashMessage message) {
160 this.syncProcessor.processNewBlockHash(sender, message);
161 }
162
163 public void apply(SkeletonResponseMessage message) {
164 this.syncProcessor.processSkeletonResponse(sender, message);
165 }
166
167 public void apply(BlockHeadersResponseMessage message) {
168 this.syncProcessor.processBlockHeadersResponse(sender, message);
169 }
170
171 public void apply(BodyRequestMessage message) {
172 final byte[] hash = message.getBlockHash();
173 this.blockProcessor.processBodyRequest(sender, message.getId(), hash);
174 }
175
176 public void apply(BodyResponseMessage message) {
177 this.syncProcessor.processBodyResponse(sender, message);
178 }
179
180 public void apply(NewBlockHashesMessage message) {
181 if (blockProcessor.hasBetterBlockToSync()) {
182 loggerMessageProcess.debug("Message[{}] not processed.", message.getMessageType());
183 return;
184 }
185 blockProcessor.processNewBlockHashesMessage(sender, message);
186 }
187
188 public void apply(TransactionsMessage message) {
189 if (blockProcessor.hasBetterBlockToSync()) {
190 loggerMessageProcess.debug("Message[{}] not processed.", message.getMessageType());
191 return;
192 }
193
194 long start = System.nanoTime();
195 loggerMessageProcess.debug("Tx message about to be process: {}", message.getMessageContentInfo());
196
197 List<Transaction> messageTxs = message.getTransactions();
198 List<Transaction> txs = new LinkedList<>();
199
200 for (Transaction tx : messageTxs) {
201 if (!tx.acceptTransactionSignature(config.getNetworkConstants().getChainId())) {
202 recordEventForPeerScoring(sender, EventType.INVALID_TRANSACTION);
203 } else {
204 txs.add(tx);
205 recordEventForPeerScoring(sender, EventType.VALID_TRANSACTION);
206 }
207 }
208
209 transactionGateway.receiveTransactionsFrom(txs, Collections.singleton(sender.getPeerNodeID()));
210
211 if (loggerMessageProcess.isDebugEnabled()) {
212 loggerMessageProcess.debug("Tx message process finished after [{}] seconds.", FormatUtils.formatNanosecondsToSeconds(System.nanoTime() - start));
213 }
214 }
215
216 private void recordEventForPeerScoring(Peer sender, EventType event) {
217 if (sender == null) {
218 return;
219 }
220
221 this.peerScoringManager.recordEvent(sender.getPeerNodeID(), sender.getAddress(), event);
222 }
223
224 private void tryRelayBlock(Block block, BlockProcessResult result) {
225 // is new block and it is not orphan, it is in some blockchain
226 if ((result.isScheduledForProcessing() || result.wasBlockAdded(block)) && !this.blockProcessor.hasBetterBlockToSync()) {
227 relayBlock(block);
228 }
229 }
230
231 private void relayBlock(Block block) {
232 Keccak256 blockHash = block.getHash();
233 final BlockNodeInformation nodeInformation = this.blockProcessor.getNodeInformation();
234 final Set<NodeID> nodesWithBlock = nodeInformation.getNodesByBlock(block.getHash());
235 final Set<NodeID> newNodes = this.syncProcessor.getKnownPeersNodeIDs().stream()
236 .filter(p -> !nodesWithBlock.contains(p))
237 .collect(Collectors.toSet());
238
239 List<BlockIdentifier> identifiers = new ArrayList<>();
240 identifiers.add(new BlockIdentifier(blockHash.getBytes(), block.getNumber()));
241 channelManager.broadcastBlockHash(identifiers, newNodes);
242 }
243 }