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 }