/*
* Copyright (c) [2016] [ <ether.camp> ]
* This file is part of the ethereumJ library.
*
* The ethereumJ library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* The ethereumJ library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with the ethereumJ library. If not, see <http://www.gnu.org/licenses/>.
*/
package org.ethereum.net.eth.handler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import org.ethereum.db.BlockStore;
import org.ethereum.listener.EthereumListener;
import org.ethereum.config.SystemProperties;
import org.ethereum.core.*;
import org.ethereum.listener.CompositeEthereumListener;
import org.ethereum.listener.EthereumListenerAdapter;
import org.ethereum.net.MessageQueue;
import org.ethereum.net.eth.EthVersion;
import org.ethereum.net.eth.message.*;
import org.ethereum.net.message.ReasonCode;
import org.ethereum.net.server.Channel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.List;
/**
* Process the messages between peers with 'eth' capability on the network<br>
* Contains common logic to all supported versions
* delegating version specific stuff to its descendants
*
*/
public abstract class EthHandler extends SimpleChannelInboundHandler<EthMessage> implements Eth {
private final static Logger logger = LoggerFactory.getLogger("net");
protected Blockchain blockchain;
protected SystemProperties config;
protected CompositeEthereumListener ethereumListener;
protected Channel channel;
private MessageQueue msgQueue = null;
protected EthVersion version;
protected boolean peerDiscoveryMode = false;
protected Block bestBlock;
protected EthereumListener listener = new EthereumListenerAdapter() {
@Override
public void onBlock(Block block, List<TransactionReceipt> receipts) {
bestBlock = block;
}
};
protected boolean processTransactions = false;
protected EthHandler(EthVersion version) {
this.version = version;
}
protected EthHandler(final EthVersion version, final SystemProperties config,
final Blockchain blockchain, final BlockStore blockStore,
final CompositeEthereumListener ethereumListener) {
this.version = version;
this.config = config;
this.ethereumListener = ethereumListener;
this.blockchain = blockchain;
bestBlock = blockStore.getBestBlock();
this.ethereumListener.addListener(listener);
// when sync enabled we delay transactions processing until sync is complete
processTransactions = !config.isSyncEnabled();
}
@Override
public void channelRead0(final ChannelHandlerContext ctx, EthMessage msg) throws InterruptedException {
if (EthMessageCodes.inRange(msg.getCommand().asByte(), version))
logger.trace("EthHandler invoke: [{}]", msg.getCommand());
ethereumListener.trace(String.format("EthHandler invoke: [%s]", msg.getCommand()));
channel.getNodeStatistics().ethInbound.add();
msgQueue.receivedMessage(msg);
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
logger.warn("Eth handling failed", cause);
ctx.close();
}
@Override
public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
logger.debug("handlerRemoved: kill timers in EthHandler");
ethereumListener.removeListener(listener);
onShutdown();
}
public void activate() {
logger.debug("ETH protocol activated");
ethereumListener.trace("ETH protocol activated");
sendStatus();
}
protected void disconnect(ReasonCode reason) {
msgQueue.disconnect(reason);
channel.getNodeStatistics().nodeDisconnectedLocal(reason);
}
protected void sendMessage(EthMessage message) {
msgQueue.sendMessage(message);
channel.getNodeStatistics().ethOutbound.add();
}
public StatusMessage getHandshakeStatusMessage() {
return channel.getNodeStatistics().getEthLastInboundStatusMsg();
}
public void setMsgQueue(MessageQueue msgQueue) {
this.msgQueue = msgQueue;
}
public void setPeerDiscoveryMode(boolean peerDiscoveryMode) {
this.peerDiscoveryMode = peerDiscoveryMode;
}
public void setChannel(Channel channel) {
this.channel = channel;
}
@Override
public EthVersion getVersion() {
return version;
}
}