Initial commit poc6 protocol update

This commit is contained in:
nicksavers 2014-09-26 16:45:41 +02:00
parent 040129799c
commit a256c12a62
72 changed files with 1151 additions and 1179 deletions

View File

@ -40,11 +40,11 @@ public class Block {
private BlockHeader header;
/* Transactions */
private List<TransactionReceipt> txReceiptList = new CopyOnWriteArrayList<TransactionReceipt>() ;
private List<Transaction> transactionsList = new CopyOnWriteArrayList<Transaction>();
private List<TransactionReceipt> txReceiptList = new CopyOnWriteArrayList<>() ;
private List<Transaction> transactionsList = new CopyOnWriteArrayList<>();
/* Uncles */
private List<BlockHeader> uncleList = new CopyOnWriteArrayList<BlockHeader>();
private List<BlockHeader> uncleList = new CopyOnWriteArrayList<>();
/* Private */

View File

@ -1,7 +1,6 @@
package org.ethereum.net;
package org.ethereum.core;
import org.ethereum.config.SystemProperties;
import org.ethereum.core.Block;
import org.ethereum.manager.WorldManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -26,9 +25,7 @@ public class BlockQueue {
private Timer timer = new Timer("BlockQueueTimer");
public BlockQueue() {
timer.scheduleAtFixedRate(new TimerTask() {
public void run() {
nudgeQueue();
}

View File

@ -4,8 +4,8 @@ import org.ethereum.facade.Blockchain;
import org.ethereum.facade.Repository;
import org.ethereum.listener.EthereumListener;
import org.ethereum.manager.WorldManager;
import org.ethereum.net.BlockQueue;
import org.ethereum.util.AdvancedDeviceUtils;
import org.ethereum.util.ByteUtil;
import org.ethereum.vm.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -59,6 +59,7 @@ public class BlockchainImpl implements Blockchain {
private Repository repository;
private Block lastBlock;
private BigInteger totalDifficulty;
// keep the index of the chain for
// convenient usage, <block_number, block_hash>
@ -70,11 +71,13 @@ public class BlockchainImpl implements Blockchain {
this.repository = repository;
}
@Override
public long getGasPrice() {
// In case of the genesis block we don't want to rely on the min gas price
return lastBlock.isGenesis() ? lastBlock.getMinGasPrice() : INITIAL_MIN_GAS_PRICE;
}
@Override
public byte[] getLatestBlockHash() {
if (blockCache.isEmpty())
return Genesis.getInstance().getHash();
@ -82,14 +85,17 @@ public class BlockchainImpl implements Blockchain {
return getLastBlock().getHash();
}
@Override
public int getSize() {
return blockCache.size();
}
@Override
public Block getBlockByNumber(long blockNr) {
return repository.getBlock(blockNr);
}
@Override
public void add(Block block) {
if (block == null)
@ -127,7 +133,7 @@ public class BlockchainImpl implements Blockchain {
ethereumListener.onBlock(block);
}
public void processBlock(Block block) {
private void processBlock(Block block) {
if(block.isValid()) {
if (!block.isGenesis()) {
if (!CONFIG.blockChainOnly()) {
@ -142,7 +148,7 @@ public class BlockchainImpl implements Blockchain {
}
}
public void applyBlock(Block block) {
private void applyBlock(Block block) {
int i = 0;
long totalGasUsed = 0;
@ -160,11 +166,19 @@ public class BlockchainImpl implements Blockchain {
}
this.addReward(block);
this.increaseTotalDifficulty(block);
if(block.getNumber() >= CONFIG.traceStartBlock())
repository.dumpState(block, totalGasUsed, 0, null);
}
private void increaseTotalDifficulty(Block block) {
totalDifficulty.add(new BigInteger(block.getDifficulty()));
for (BlockHeader uncleHeader : block.getUncleList()) {
totalDifficulty.add(new BigInteger(uncleHeader.getDifficulty()));
}
}
/**
* Add reward to block- and every uncle coinbase
* assuming the entire block is valid.
@ -190,6 +204,7 @@ public class BlockchainImpl implements Blockchain {
repository.addBalance(block.getCoinbase(), totalBlockReward);
}
@Override
public void storeBlock(Block block) {
/* Debug check to see if the state is still as expected */
@ -433,23 +448,33 @@ public class BlockchainImpl implements Blockchain {
}
}
@Override
public BlockQueue getBlockQueue() {
return blockQueue;
}
@Override
public Map<Long, byte[]> getBlockCache() {
return this.blockCache;
}
@Override
public Block getLastBlock() {
return lastBlock;
}
@Override
public void setLastBlock(Block block) {
this.lastBlock = block;
}
@Override
public void close(){
blockQueue.close();
}
@Override
public byte[] getTotalDifficulty() {
return ByteUtil.bigIntegerToBytes(totalDifficulty);
}
}

View File

@ -120,7 +120,7 @@ public class DatabaseImpl implements Database {
public List<ByteArrayWrapper> dumpKeys() {
DBIterator iterator = getDb().iterator();
ArrayList<ByteArrayWrapper> keys = new ArrayList<ByteArrayWrapper>();
ArrayList<ByteArrayWrapper> keys = new ArrayList<>();
while (iterator.hasNext()) {
ByteArrayWrapper key = new ByteArrayWrapper(iterator.next().getKey());

View File

@ -3,9 +3,9 @@ package org.ethereum.db;
import org.codehaus.plexus.util.FileUtils;
import org.ethereum.core.AccountState;
import org.ethereum.core.Block;
import org.ethereum.core.BlockchainImpl;
import org.ethereum.core.Genesis;
import org.ethereum.crypto.HashUtil;
import org.ethereum.facade.Blockchain;
import org.ethereum.facade.Repository;
import org.ethereum.json.EtherObjectMapper;
import org.ethereum.json.JSONHelper;
@ -128,8 +128,8 @@ public class RepositoryImpl implements Repository {
this.worldState.sync();
}
public BlockchainImpl loadBlockchain() {
BlockchainImpl blockchain = WorldManager.getInstance().getBlockchain();
public Blockchain loadBlockchain() {
Blockchain blockchain = WorldManager.getInstance().getBlockchain();
DBIterator iterator = chainDB.iterator();
try {
if (!iterator.hasNext()) {
@ -161,8 +161,7 @@ public class RepositoryImpl implements Repository {
}
logger.debug("Block #{} -> {}", block.getNumber(), block.toFlatString());
}
logger.info(
"*** Loaded up to block [ {} ] with stateRoot [ {} ]",
logger.info("*** Loaded up to block [{}] with stateRoot [{}]",
blockchain.getLastBlock().getNumber(),
Hex.toHexString(blockchain.getLastBlock().getStateRoot()));
}

View File

@ -1,11 +1,22 @@
package org.ethereum.facade;
import java.util.Map;
import org.ethereum.core.Block;
import org.ethereum.core.BlockQueue;
public interface Blockchain {
public int getSize();
public void add(Block block);
public void storeBlock(Block block);
public Map<Long, byte[]> getBlockCache();
public Block getBlockByNumber(long blockNr);
public long getGasPrice();
public void setLastBlock(Block block);
public Block getLastBlock();
public BlockQueue getBlockQueue();
public void close();
public byte[] getTotalDifficulty();
public byte[] getLatestBlockHash();
}

View File

@ -5,7 +5,7 @@ import org.ethereum.core.Wallet;
import org.ethereum.facade.Repository;
import org.ethereum.listener.EthereumListener;
import org.ethereum.net.client.ClientPeer;
import org.ethereum.net.client.PeerData;
import org.ethereum.net.client.Peer;
import java.net.InetAddress;
import java.util.Set;
@ -25,7 +25,7 @@ public interface Ethereum {
* @param excludePeer - peer to exclude
* @return online peer if available otherwise null
*/
public PeerData findOnlinePeer(PeerData excludePeer) ;
public Peer findOnlinePeer(Peer excludePeer) ;
/**
* Find an online peer but not from excluded list
@ -33,12 +33,12 @@ public interface Ethereum {
* @param excludePeerSet - peers to exclude
* @return online peer if available otherwise null
*/
public PeerData findOnlinePeer(Set<PeerData> excludePeerSet) ;
public Peer findOnlinePeer(Set<Peer> excludePeerSet) ;
/**
* @return online peer if available
*/
public PeerData findOnlinePeer();
public Peer findOnlinePeer();
/**
@ -46,7 +46,7 @@ public interface Ethereum {
*
* @return online peer.
*/
public PeerData waitForOnlinePeer();
public Peer waitForOnlinePeer();
/*
*
@ -59,7 +59,7 @@ public interface Ethereum {
* }
*
*/
public Set<PeerData> getPeers();
public Set<Peer> getPeers();
public void startPeerDiscovery();
public void stopPeerDiscovery();

View File

@ -10,7 +10,7 @@ import org.ethereum.core.Wallet;
import org.ethereum.listener.EthereumListener;
import org.ethereum.manager.WorldManager;
import org.ethereum.net.client.ClientPeer;
import org.ethereum.net.client.PeerData;
import org.ethereum.net.client.Peer;
import org.ethereum.net.submit.TransactionExecutor;
import org.ethereum.net.submit.TransactionTask;
import org.slf4j.Logger;
@ -37,24 +37,24 @@ public class EthereumImpl implements Ethereum {
* @return online peer
*/
@Override
public PeerData findOnlinePeer(PeerData peerData) {
public Peer findOnlinePeer(Peer peerData) {
Set<PeerData> excludePeers = new HashSet<>();
Set<Peer> excludePeers = new HashSet<>();
excludePeers.add(peerData);
return findOnlinePeer(excludePeers);
}
@Override
public PeerData findOnlinePeer() {
public Peer findOnlinePeer() {
Set<PeerData> excludePeers = new HashSet<>();
Set<Peer> excludePeers = new HashSet<>();
return findOnlinePeer(excludePeers);
}
@Override
public PeerData findOnlinePeer(Set<PeerData> excludePeers) {
public Peer findOnlinePeer(Set<Peer> excludePeers) {
logger.info("Looking for online peers...");
final EthereumListener listener = WorldManager.getInstance().getListener();
@ -64,10 +64,10 @@ public class EthereumImpl implements Ethereum {
WorldManager.getInstance().startPeerDiscovery();
final Set<PeerData> peers = WorldManager.getInstance().getPeers();
final Set<Peer> peers = WorldManager.getInstance().getPeers();
synchronized (peers) {
for (PeerData peer : peers) { // it blocks until a peer is available.
for (Peer peer : peers) { // it blocks until a peer is available.
if (peer.isOnline() && !excludePeers.contains(peer)) {
@ -85,9 +85,9 @@ public class EthereumImpl implements Ethereum {
@Override
public PeerData waitForOnlinePeer(){
public Peer waitForOnlinePeer(){
PeerData peer = null;
Peer peer = null;
while(peer == null){
try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}
@ -99,7 +99,7 @@ public class EthereumImpl implements Ethereum {
@Override
public Set<PeerData> getPeers() {
public Set<Peer> getPeers() {
return WorldManager.getInstance().getPeers();
}

View File

@ -4,7 +4,6 @@ import java.math.BigInteger;
import org.ethereum.core.AccountState;
import org.ethereum.core.Block;
import org.ethereum.core.BlockchainImpl;
import org.ethereum.db.ContractDetails;
import org.ethereum.trie.Trie;
import org.ethereum.vm.DataWord;
@ -151,7 +150,7 @@ public interface Repository {
*
* @return the <code>Blockchain</code> object
*/
public BlockchainImpl loadBlockchain();
public Blockchain loadBlockchain();
/**
* Dump the full state of the current repository into a file with JSON format

View File

@ -57,7 +57,6 @@ public class AccountState {
if (hexVal) {
key = new ByteArrayWrapper(Hex.decode(keyS.substring(2)));
} else {
byte[] data = ByteUtil.bigIntegerToBytes(new BigInteger(keyS));
key = new ByteArrayWrapper(data);
}
@ -67,14 +66,11 @@ public class AccountState {
if (hexVal) {
value = new ByteArrayWrapper(Hex.decode(valS.substring(2)));
} else {
byte[] data = ByteUtil.bigIntegerToBytes(new BigInteger(valS));
value = new ByteArrayWrapper(data);
}
storage.put(key, value);
}
}
public byte[] getAddress() {

View File

@ -206,8 +206,7 @@ public class TestRunner {
resultCallCreate = resultCallCreates.get(i);
}
CallCreate expectedCallCreate =
testCase.getCallCreateList().get(i);
CallCreate expectedCallCreate = testCase.getCallCreateList().get(i);
if (resultCallCreate == null && expectedCallCreate != null) {
@ -223,7 +222,8 @@ public class TestRunner {
continue;
}
boolean assertDestination = Arrays.equals(expectedCallCreate.getDestination(),
boolean assertDestination = Arrays.equals(
expectedCallCreate.getDestination(),
resultCallCreate.getDestination());
if (!assertDestination) {
@ -235,7 +235,8 @@ public class TestRunner {
results.add(output);
}
boolean assertData = Arrays.equals(expectedCallCreate.getData(),
boolean assertData = Arrays.equals(
expectedCallCreate.getData(),
resultCallCreate.getData());
if (!assertData) {
@ -247,10 +248,10 @@ public class TestRunner {
results.add(output);
}
boolean assertGasLimit = Arrays.equals(expectedCallCreate.getGasLimit(),
boolean assertGasLimit = Arrays.equals(
expectedCallCreate.getGasLimit(),
resultCallCreate.getGasLimit());
if (!assertGasLimit) {
String output =
String.format("Call/Create gasLimit is different expected: [ %s ], result: [ %s ]",
Hex.toHexString(expectedCallCreate.getGasLimit()),
@ -259,10 +260,10 @@ public class TestRunner {
results.add(output);
}
boolean assertValue = Arrays.equals(expectedCallCreate.getValue(),
boolean assertValue = Arrays.equals(
expectedCallCreate.getValue(),
resultCallCreate.getValue());
if (!assertValue) {
String output =
String.format("Call/Create value is different expected: [ %s ], result: [ %s ]",
Hex.toHexString(expectedCallCreate.getValue()),

View File

@ -10,10 +10,11 @@ import org.ethereum.core.BlockchainImpl;
import org.ethereum.core.Wallet;
import org.ethereum.crypto.HashUtil;
import org.ethereum.db.RepositoryImpl;
import org.ethereum.facade.Blockchain;
import org.ethereum.facade.Repository;
import org.ethereum.listener.EthereumListener;
import org.ethereum.net.client.ClientPeer;
import org.ethereum.net.client.PeerData;
import org.ethereum.net.client.Peer;
import org.ethereum.net.peerdiscovery.PeerDiscovery;
/**
@ -26,13 +27,13 @@ import org.ethereum.net.peerdiscovery.PeerDiscovery;
*/
public class WorldManager {
private BlockchainImpl blockchain;
private Blockchain blockchain;
private Repository repository;
private Wallet wallet;
private PeerDiscovery peerDiscovery;
private final Set<PeerData> peers = Collections.synchronizedSet(new HashSet<PeerData>());
private final Set<Peer> peers = Collections.synchronizedSet(new HashSet<Peer>());
private ClientPeer activePeer;
@ -50,11 +51,10 @@ public class WorldManager {
this.blockchain = new BlockchainImpl(repository);
// Initialize PeerData
List<PeerData> peerDataList = parsePeerDiscoveryIpList(CONFIG.peerDiscoveryIPList());
List<Peer> peerDataList = parsePeerDiscoveryIpList(CONFIG.peerDiscoveryIPList());
peers.addAll(peerDataList);
peerDiscovery = new PeerDiscovery(peers);
}
// used for testing
@ -85,10 +85,10 @@ public class WorldManager {
this.listener = listener;
}
public void addPeers(final Set<PeerData> newPeers) {
public void addPeers(final Set<Peer> newPeers) {
synchronized (peers) {
for (final PeerData peer : newPeers) {
for (final Peer peer : newPeers) {
if (peerDiscovery.isStarted() && !peers.contains(peer)) {
peerDiscovery.addNewPeerData(peer);
}
@ -116,10 +116,10 @@ public class WorldManager {
return listener;
}
public List<PeerData> parsePeerDiscoveryIpList(final String peerDiscoveryIpList){
public List<Peer> parsePeerDiscoveryIpList(final String peerDiscoveryIpList) {
final List<String> ipList = Arrays.asList(peerDiscoveryIpList.split(","));
final List<PeerData> peers = new ArrayList<>();
final List<Peer> peers = new ArrayList<>();
for (String ip : ipList){
String[] addr = ip.trim().split(":");
@ -130,13 +130,12 @@ public class WorldManager {
InetAddress iAddr = InetAddress.getByName(ip_trim);
int port = Integer.parseInt(port_trim);
PeerData peerData = new PeerData(iAddr.getAddress(), port, new byte[]{00});
Peer peerData = new Peer(iAddr.getAddress(), port, new byte[]{00});
peers.add(peerData);
} catch (UnknownHostException e) {
e.printStackTrace();
}
}
return peers;
}
@ -148,7 +147,7 @@ public class WorldManager {
return repository;
}
public BlockchainImpl getBlockchain() {
public Blockchain getBlockchain() {
return blockchain;
}
@ -168,7 +167,7 @@ public class WorldManager {
return activePeer;
}
public Set<PeerData> getPeers() {
public Set<Peer> getPeers() {
return peers;
}

View File

@ -90,7 +90,7 @@ public enum Command {
private int cmd;
private static final Map<Integer, Command> intToTypeMap = new HashMap<Integer, Command>();
private static final Map<Integer, Command> intToTypeMap = new HashMap<>();
static {
for (Command type : Command.values()) {
intToTypeMap.put(type.cmd, type);

View File

@ -9,16 +9,13 @@ import io.netty.channel.MessageSizeEstimator;
* @author: Roman Mandeleil
* Created on: 04/07/2014 13:16
*/
public class EthereumMessageSizeEstimator implements MessageSizeEstimator {
private final Handle handle = new HandleImpl();
private static final class HandleImpl implements Handle {
private HandleImpl() {
}
@Override
@ -26,12 +23,13 @@ public class EthereumMessageSizeEstimator implements MessageSizeEstimator {
ByteBuf buffer = ((ByteBuf)msg);
if (buffer.readableBytes() < 8) throw new RuntimeException("Not Ethereum packet");
if (buffer.readableBytes() < 8)
throw new RuntimeException("Not an Ethereum packet");
int msgSize = ((buffer.getByte(4) & 0xFF) << 24) +
((buffer.getByte(5) & 0xFF) << 16) +
((buffer.getByte(6) & 0xFF) << 8) +
((buffer.getByte(7) & 0xFF));
return msgSize;
}
}

View File

@ -56,8 +56,11 @@ public class MessageQueue {
if (logger.isDebugEnabled())
logger.debug("Recv: [{}] - [{}]",
msg.getMessageName(),
Hex.toHexString(msg.getPayload()));
msg.getCommand().name(),
Hex.toHexString(msg.getEncoded()));
if (logger.isInfoEnabled())
logger.info("Recv: {}", msg.toString());
if (null != messageQueue.peek()) {
@ -69,7 +72,7 @@ public class MessageQueue {
if (msg.getClass() == waitingMessage.getAnswerMessage()){
messageRoundtrip.answer();
logger.debug("Message round trip covered: [ {} ] ", messageRoundtrip.getMsg().getMessageName());
logger.debug("Message round trip covered: [{}] ", messageRoundtrip.getMsg().getCommand());
}
}
}
@ -109,17 +112,20 @@ public class MessageQueue {
if (logger.isDebugEnabled())
logger.debug("Send: [{}] - [{}]",
msg.getMessageName(),
Hex.toHexString(msg.getPayload()));
msg.getCommand().name(),
Hex.toHexString(msg.getEncoded()));
ByteBuf buffer = ctx.alloc().buffer(msg.getPayload().length + 8);
if (logger.isInfoEnabled())
logger.info("Send: {}", msg.toString());
int packetLength = StaticMessages.SYNC_TOKEN.length + msg.getEncoded().length;
ByteBuf buffer = ctx.alloc().buffer(packetLength);
buffer.writeBytes(StaticMessages.SYNC_TOKEN);
buffer.writeBytes(ByteUtil.calcPacketLength(msg.getPayload()));
buffer.writeBytes(msg.getPayload());
buffer.writeBytes(ByteUtil.calcPacketLength(msg.getEncoded()));
buffer.writeBytes(msg.getEncoded());
ctx.writeAndFlush(buffer);
}
private boolean containsGetBlockHashes() {
Iterator<MessageRoundtrip> iterator = messageQueue.iterator();
while(iterator.hasNext()){

View File

@ -77,7 +77,6 @@ public class ClientPeer {
// Wait until the connection is closed.
f.channel().closeFuture().sync();
} catch (InterruptedException ie) {
logger.error("-- ClientPeer: catch (InterruptedException ie) --", ie);
} finally {
@ -85,10 +84,10 @@ public class ClientPeer {
handler.killTimers();
final Set<PeerData> peers = WorldManager.getInstance().getPeers();
final Set<Peer> peers = WorldManager.getInstance().getPeers();
synchronized (peers) {
for (PeerData peer : peers){
for (Peer peer : peers) {
if (host.equals(peer.getInetAddress().getHostAddress()) &&
port == peer.getPort()){
peer.setOnline(false);
@ -97,10 +96,7 @@ public class ClientPeer {
}
EthereumListener listener = WorldManager.getInstance().getListener();
if (listener != null){
listener.onPeerDisconnect(host, port);
}
if (listener != null) listener.onPeerDisconnect(host, port);
}
}
@ -108,25 +104,20 @@ public class ClientPeer {
this.peerListener = peerListener;
}
/*
* The wire gets data for signed transactions and
* sends it to the net.
*/
public void sendTransaction(Transaction transaction) {
transaction.getEncoded();
java.util.List<Transaction> txList = new ArrayList<Transaction>();
List<Transaction> txList = new ArrayList<>();
txList.add(transaction);
TransactionsMessage transactionsMessage = new TransactionsMessage(txList);
byte[] payload = transactionsMessage.getPayload();
byte[] payload = transactionsMessage.getEncoded();
if (peerListener != null)
peerListener.console("Send msg: [ " +
Hex.toHexString(payload) +
" ]");
peerListener.console("Send msg: [" + Hex.toHexString(payload) + "]");
handler.sendMsg(transactionsMessage);
}

View File

@ -1,24 +1,21 @@
package org.ethereum.net.client;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.ChannelOption;
import io.netty.channel.FixedRecvByteBufAllocator;
import org.ethereum.config.SystemProperties;
import org.ethereum.core.Block;
import org.ethereum.core.Transaction;
import org.ethereum.listener.EthereumListener;
import org.ethereum.manager.WorldManager;
import org.ethereum.net.Command;
import org.ethereum.net.MessageQueue;
import org.ethereum.net.PeerListener;
import org.ethereum.net.message.*;
import org.ethereum.net.peerdiscovery.PeerProtocolHandler;
import org.ethereum.util.RLP;
import org.ethereum.util.RLPList;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.spongycastle.util.encoders.Hex;
import java.util.List;
import java.util.Timer;
@ -31,59 +28,39 @@ import static org.ethereum.net.message.StaticMessages.*;
* @author: Roman Mandeleil
* Created on: 10/04/14 08:19
*/
public class EthereumProtocolHandler extends ChannelInboundHandlerAdapter {
public class EthereumProtocolHandler extends PeerProtocolHandler {
private Logger logger = LoggerFactory.getLogger("wire");
private Timer blocksAskTimer = new Timer("ChainAskTimer");
private final Timer timer = new Timer("MiscMessageTimer");
private int secToAskForBlocks = 1;
private boolean tearDown = false;
private PeerListener peerListener;
private MessageQueue msgQueue = null;
public EthereumProtocolHandler() { }
public EthereumProtocolHandler(PeerListener peerListener) {
this.peerListener = peerListener;
super(peerListener);
}
@Override
public void channelActive(final ChannelHandlerContext ctx) {
msgQueue = new MessageQueue(ctx);
logger.info("Send: " + StaticMessages.HELLO_MESSAGE.toString());
msgQueue.sendMessage(StaticMessages.HELLO_MESSAGE);
sendPing();
// sample for pinging in background
super.channelActive(ctx);
sendGetBlockHashes();
timer.scheduleAtFixedRate(new TimerTask() {
public void run() {
if (tearDown) this.cancel();
sendPing();
}
}, 2000, 5000);
timer.scheduleAtFixedRate(new TimerTask() {
public void run() {
sendGetPeers();
}
}, 2000, 60000);
timer.scheduleAtFixedRate(new TimerTask() {
public void run() {
sendGetTransactions();
}
}, 2000, 10000);
blocksAskTimer.scheduleAtFixedRate(new TimerTask() {
timer.scheduleAtFixedRate(new TimerTask() {
public void run() {
sendGetBlockHashes();
}
}, 2000, 10000);
blocksAskTimer.scheduleAtFixedRate(new TimerTask() {
public void run() {
sendGetBlocks();
}
@ -92,89 +69,28 @@ public class EthereumProtocolHandler extends ChannelInboundHandlerAdapter {
}
@Override
public void channelRead(final ChannelHandlerContext ctx, Object msg) throws Exception {
public void channelRead(final ChannelHandlerContext ctx, Object msg) throws InterruptedException {
super.channelRead(ctx, msg);
byte[] payload = (byte[]) msg;
logger.info("[Recv msg: [{}] ]", Hex.toHexString(payload));
EthereumListener listener = WorldManager.getInstance().getListener();
byte commandCode = RLP.getCommandCode(payload);
Command receivedCommand = Command.fromInt(commandCode);
logger.info("[Recv: {}]", receivedCommand.name());
Command receivedCommand = Command.fromInt(RLP.getCommandCode(payload));
if (peerListener != null) peerListener.console("[Recv: " + receivedCommand.name() + "]");
switch(receivedCommand) {
case HELLO:
RLPList rlpList = RLP.decode2(payload);
HelloMessage helloMessage = new HelloMessage(rlpList);
logger.info(helloMessage.toString());
if (peerListener != null) peerListener.console(helloMessage.toString());
if (listener != null){
listener.trace(String.format("Got handshake: [ %s ]", helloMessage.toString()));
listener.onRecvMessage(helloMessage);
}
break;
case DISCONNECT:
DisconnectMessage disconnectMessage = new DisconnectMessage(payload);
msgQueue.receivedMessage(disconnectMessage);
logger.info(disconnectMessage.toString());
if (peerListener != null) peerListener.console(disconnectMessage.toString());
if (listener != null)
listener.onRecvMessage(disconnectMessage);
break;
case PING:
msgQueue.receivedMessage(PING_MESSAGE);
sendPong();
if (listener != null)
listener.onRecvMessage(PING_MESSAGE);
break;
case PONG:
msgQueue.receivedMessage(PONG_MESSAGE);
if (listener != null)
listener.onRecvMessage(PONG_MESSAGE);
break;
case GET_PEERS:
msgQueue.receivedMessage(GET_PEERS_MESSAGE);
// TODO: send peer list
if (listener != null)
listener.onRecvMessage(GET_PEERS_MESSAGE);
break;
case PEERS:
PeersMessage peersMessage = new PeersMessage(payload);
msgQueue.receivedMessage(peersMessage);
WorldManager.getInstance().addPeers(peersMessage.getPeers());
logger.info(peersMessage.toString());
if (peerListener != null) peerListener.console(peersMessage.toString());
if (listener != null)
listener.onRecvMessage(peersMessage);
sendStatus();
break;
case TRANSACTIONS:
TransactionsMessage transactionsMessage = new TransactionsMessage(payload);
msgQueue.receivedMessage(transactionsMessage);
if (peerListener != null) peerListener.console(transactionsMessage.toString());
List<Transaction> txList = transactionsMessage.getTransactions();
for(Transaction tx : txList)
// WorldManager.getInstance().getBlockchain()
// .applyTransaction(null, tx);
// WorldManager.getInstance().getBlockchain().applyTransaction(null, tx);
WorldManager.getInstance().getWallet().addTransaction(tx);
logger.info(transactionsMessage.toString());
if (peerListener != null) peerListener.console(transactionsMessage.toString());
if (listener != null)
listener.onRecvMessage(transactionsMessage);
break;
@ -182,45 +98,22 @@ public class EthereumProtocolHandler extends ChannelInboundHandlerAdapter {
BlocksMessage blocksMessage = new BlocksMessage(payload);
List<Block> blockList = blocksMessage.getBlockDataList();
msgQueue.receivedMessage(blocksMessage);
if (peerListener != null) peerListener.console(blocksMessage.toString());
// If we get one block from a peer we ask less greedy
if (blockList.size() <= 1 && secToAskForBlocks != 10) {
logger.info("Now we ask for blocks each 10 seconds");
secToAskForBlocks = 10;
blocksAskTimer.cancel();
blocksAskTimer.purge();
blocksAskTimer = new Timer();
blocksAskTimer.scheduleAtFixedRate(new TimerTask() {
public void run() {
sendGetBlocks();
}
}, 3000, secToAskForBlocks * 1000);
logger.info("Now we ask for blocks every 10 seconds");
updateBlockAskTimer(10);
}
// If we get more blocks from a peer we ask more greedy
if (blockList.size() > 2 && secToAskForBlocks != 1) {
logger.info("Now we ask for a chain each 1 seconds");
secToAskForBlocks = 1;
blocksAskTimer.cancel();
blocksAskTimer.purge();
blocksAskTimer = new Timer();
blocksAskTimer.scheduleAtFixedRate(new TimerTask() {
public void run() {
sendGetBlocks();
}
}, 3000, secToAskForBlocks * 1000);
logger.info("Now we ask for a chain every 1 seconds");
updateBlockAskTimer(1);
}
if (blockList.isEmpty()) return;
WorldManager.getInstance().getBlockchain().getBlockQueue().addBlocks(blockList);
if (peerListener != null) peerListener.console(blocksMessage.toString());
if (listener != null)
listener.onRecvMessage(blocksMessage);
break;
@ -238,13 +131,32 @@ public class EthereumProtocolHandler extends ChannelInboundHandlerAdapter {
listener.onRecvMessage(GET_TRANSACTIONS_MESSAGE);
break;
case GET_BLOCK_HASHES:
// TODO Implement GET_BLOCK_HASHES command
GetBlockHashesMessage getBlockHashesMessage = new GetBlockHashesMessage(payload);
msgQueue.receivedMessage(getBlockHashesMessage);
if (peerListener != null) peerListener.console(getBlockHashesMessage.toString());
sendBlockHashes();
if (listener != null)
listener.onRecvMessage(getBlockHashesMessage);
break;
case BLOCK_HASHES:
// TODO Implement BLOCK_HASHES command
BlockHashesMessage blockHashesMessage = new BlockHashesMessage(payload);
msgQueue.receivedMessage(blockHashesMessage);
if (peerListener != null) peerListener.console(blockHashesMessage.toString());
// TODO Process Block Hashes
if (listener != null)
listener.onRecvMessage(blockHashesMessage);
break;
case GET_BLOCKS:
// TODO Implement GET_BLOCKS command
GetBlocksMessage getBlocksMessage = new GetBlocksMessage(payload);
msgQueue.receivedMessage(getBlocksMessage);
sendBlocks();
if (listener != null)
listener.onRecvMessage(getBlocksMessage);
break;
default:
// do nothing and ignore this command
@ -252,6 +164,18 @@ public class EthereumProtocolHandler extends ChannelInboundHandlerAdapter {
}
}
private void updateBlockAskTimer(int seconds) {
secToAskForBlocks = seconds;
blocksAskTimer.cancel();
blocksAskTimer.purge();
blocksAskTimer = new Timer();
blocksAskTimer.scheduleAtFixedRate(new TimerTask() {
public void run() {
sendGetBlocks();
}
}, 3000, secToAskForBlocks * 1000);
}
@Override
public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
// limit the size of recieving buffer to 1024
@ -260,7 +184,7 @@ public class EthereumProtocolHandler extends ChannelInboundHandlerAdapter {
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws InterruptedException {
this.tearDown = true;
logger.info("Lost connection to the server");
logger.error(cause.getMessage(), cause);
@ -268,30 +192,26 @@ public class EthereumProtocolHandler extends ChannelInboundHandlerAdapter {
timer.cancel();
}
public void sendMsg(Message msg) {
msgQueue.sendMessage(msg);
EthereumListener listener = WorldManager.getInstance().getListener();
if (listener != null)
listener.onSendMessage(msg);
}
private void sendPing() {
sendMsg(PING_MESSAGE);
}
private void sendPong() {
sendMsg(PONG_MESSAGE);
}
private void sendGetPeers() {
sendMsg(GET_PEERS_MESSAGE);
protected void sendStatus() {
byte protocolVersion = 0, networkId = 0;
byte[] totalDifficulty = WorldManager.getInstance().getBlockchain().getTotalDifficulty();
byte[] bestHash = WorldManager.getInstance().getBlockchain().getLatestBlockHash();
byte[] genesisHash = StaticMessages.GENESIS_HASH;
StatusMessage peersMessage = new StatusMessage(protocolVersion, networkId,
totalDifficulty, bestHash, genesisHash);
sendMsg(peersMessage);
}
private void sendGetTransactions() {
sendMsg(GET_TRANSACTIONS_MESSAGE);
}
private void sendGetBlockHashes() {
byte[] lastHash = WorldManager.getInstance().getBlockchain().getLatestBlockHash();
GetBlockHashesMessage getBlockHashesMessage = new GetBlockHashesMessage(lastHash, 128);
sendMsg(getBlockHashesMessage);
}
private void sendGetBlocks() {
if (WorldManager.getInstance().getBlockchain().getBlockQueue().size() >
@ -306,6 +226,14 @@ public class EthereumProtocolHandler extends ChannelInboundHandlerAdapter {
sendMsg(getBlocksMessage);
}
private void sendBlocks() {
// TODO: Send blocks
}
private void sendBlockHashes() {
// TODO: Send block hashes
}
public void killTimers(){
blocksAskTimer.cancel();
blocksAskTimer.purge();

View File

@ -1,31 +1,35 @@
package org.ethereum.net.client;
import org.ethereum.net.message.HelloMessage;
import org.ethereum.util.RLP;
import org.spongycastle.util.encoders.Hex;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.List;
/**
* www.ethereumJ.com
* @author: Roman Mandeleil
* Created on: 13/04/14 17:36
*/
public class PeerData {
public class Peer {
private byte[] ip;
private int port;
private short port;
private byte[] peerId;
private byte capabilities;
private List<String> capabilities;
private HelloMessage handshake;
private transient boolean isOnline = false;
private transient long lastCheckTime = 0;
public PeerData(byte[] ip, int port, byte[] peerId) {
public Peer(byte[] ip, int port, byte[] peerId) {
this.ip = ip;
this.port = port & 0xFFFF;
this.port = (short) (port & 0xFFFF);
this.peerId = peerId;
this.capabilities = new ArrayList<>();
}
public InetAddress getInetAddress() {
@ -52,7 +56,7 @@ public class PeerData {
}
public boolean isOnline() {
if (getCapabilities() < 7) return false;
if (getCapabilities().size() < 0) return false;
return isOnline;
}
@ -68,12 +72,12 @@ public class PeerData {
this.lastCheckTime = lastCheckTime;
}
public byte getCapabilities() {
public List<String> getCapabilities() {
if (handshake != null)
return handshake.getCapabilities();
else
return 0;
return new ArrayList<String>();
}
public HelloMessage getHandshake() {
@ -84,16 +88,30 @@ public class PeerData {
this.handshake = handshake;
}
public byte[] getEncoded() {
byte[] ip = RLP.encodeElement(this.ip);
byte[] port = RLP.encodeShort(this.port);
byte[] peerId = RLP.encodeElement(this.peerId);
byte[][] encodedCaps = new byte[this.capabilities.size()][];
for (int i = 0; i < this.capabilities.size(); i++) {
encodedCaps[i] = RLP.encodeString(this.capabilities.get(i));
}
byte[] capabilities = RLP.encodeList(encodedCaps);
return RLP.encodeList(ip, port, peerId, capabilities);
}
@Override
public String toString() {
return "Peer: [ip=" + getInetAddress().getHostAddress() + ", port=" + getPort() +
", peerId=" + (getPeerId() == null ? "": Hex.toHexString(getPeerId())) + "]";
return "[ip=" + getInetAddress().getHostAddress() +
", port=" + getPort() +
", peerId=" + (getPeerId() == null ? "" : Hex.toHexString(getPeerId()))
+ "]";
}
@Override
public boolean equals(Object obj) {
if (obj == null) return false;
PeerData peerData = (PeerData) obj;
Peer peerData = (Peer) obj;
return this.getInetAddress().equals(peerData.getInetAddress());
}

View File

@ -1,29 +1,47 @@
package org.ethereum.net.message;
import static org.ethereum.net.Command.BLOCK_HASHES;
import java.util.List;
import org.ethereum.db.ByteArrayWrapper;
import org.ethereum.net.Command;
import org.ethereum.util.RLP;
import org.ethereum.util.RLPList;
import com.google.common.base.Joiner;
public class BlockHashesMessage extends Message {
@Override
public void parseRLP() {
// TODO Auto-generated method stub
private List<ByteArrayWrapper> hashes;
public BlockHashesMessage(byte[] payload) {
super(payload);
}
private void parse() {
RLPList paramsList = (RLPList) RLP.decode2(encoded).get(0);
this.encoded = new byte[0]; // TODO
}
@Override
public byte[] getPayload() {
// TODO Auto-generated method stub
public Command getCommand() {
return BLOCK_HASHES;
}
@Override
public byte[] getEncoded() {
return encoded;
}
@Override
public Class<?> getAnswerMessage() {
return null;
}
@Override
public String getMessageName() {
// TODO Auto-generated method stub
return null;
public String toString() {
if (!parsed) parse();
return "[command=" + this.getCommand().name() + " hashes=" + Joiner.on("\n").join(hashes) + " ]";
}
@Override
public Class getAnswerMessage() {
// TODO Auto-generated method stub
return null;
}
}

View File

@ -18,25 +18,18 @@ import org.ethereum.util.RLPList;
*/
public class BlocksMessage extends Message {
private List<Block> blockDataList = new ArrayList<Block>();
private List<Block> blockDataList = new ArrayList<>();
public BlocksMessage(RLPList rawData) {
super(rawData);
public BlocksMessage(byte[] encoded) {
super(encoded);
}
public BlocksMessage(byte[] payload) {
super(RLP.decode2(payload));
this.payload = payload;
}
public void parse() {
RLPList paramsList = (RLPList) RLP.decode2(encoded).get(0);
public void parseRLP() {
RLPList paramsList = (RLPList) rawData.get(0);
if (Command.fromInt(((RLPItem) (paramsList).get(0)).getRLPData()[0]) != BLOCKS) {
throw new Error("BlocksMessage: parsing for mal data");
}
if ( (((RLPItem)(paramsList).get(0)).getRLPData()[0] & 0xFF) != BLOCKS.asByte())
throw new RuntimeException("Not a BlocksMessage command");
for (int i = 1; i < paramsList.size(); ++i) {
RLPList rlpData = ((RLPList) paramsList.get(i));
@ -47,33 +40,32 @@ public class BlocksMessage extends Message {
}
@Override
public byte[] getPayload() {
return payload;
public Command getCommand() {
return BLOCKS;
}
@Override
public byte[] getEncoded() {
return encoded;
}
public List<Block> getBlockDataList() {
if (!parsed) parseRLP();
if (!parsed) parse();
return blockDataList;
}
@Override
public String getMessageName() {
return "Block";
}
@Override
public Class getAnswerMessage() {
public Class<?> getAnswerMessage() {
return null;
}
public String toString() {
if (!parsed) parseRLP();
if (!parsed) parse();
StringBuffer sb = new StringBuffer();
for (Block blockData : this.getBlockDataList()) {
sb.append(" ").append(blockData.toFlatString()).append("\n");
}
return "Blocks Message [\n" + sb.toString() + " ]";
return "[command=" + getCommand().name() + "\n" + sb.toString() + " ]";
}
}

View File

@ -17,57 +17,45 @@ public class DisconnectMessage extends Message {
private ReasonCode reason;
public DisconnectMessage(byte[] payload) {
super(RLP.decode2(payload));
this.payload = payload;
public DisconnectMessage(byte[] encoded) {
super(encoded);
}
public DisconnectMessage(RLPList rawData) {
super(rawData);
}
private void parse() {
@Override
public void parseRLP() {
RLPList paramsList = (RLPList) rawData.get(0);
if (Command.fromInt(((RLPItem)(paramsList).get(0)).getRLPData()[0]) != DISCONNECT) {
throw new Error("Disconnect: parsing for mal data");
}
RLPList paramsList = (RLPList) RLP.decode2(encoded).get(0);
byte[] reasonB = ((RLPItem) paramsList.get(1)).getRLPData();
if (reasonB == null) {
if (reasonB == null)
this.reason = REQUESTED;
} else {
else
this.reason = ReasonCode.fromInt(reasonB[0]);
}
this.parsed = true;
// TODO: what to do when mal data ?
}
@Override
public byte[] getPayload() {
public Command getCommand() {
return DISCONNECT;
}
@Override
public byte[] getEncoded() {
return encoded;
}
@Override
public Class<?> getAnswerMessage() {
return null;
}
public ReasonCode getReason() {
if (!parsed) parseRLP();
if (!parsed) parse();
return reason;
}
@Override
public String getMessageName() {
return "Disconnect";
}
@Override
public Class getAnswerMessage() {
return null;
}
public String toString() {
if (!parsed) parseRLP();
return "Disconnect Message [ reason=" + reason + " ]";
if (!parsed) parse();
return "[command=" + this.getCommand().name() + " reason=" + reason + "]";
}
}

View File

@ -1,19 +1,57 @@
package org.ethereum.net.message;
import java.math.BigInteger;
import static org.ethereum.net.Command.GET_BLOCK_HASHES;
import org.ethereum.net.Command;
import org.ethereum.util.RLP;
import org.ethereum.util.RLPItem;
import org.ethereum.util.RLPList;
public class GetBlockHashesMessage extends Message {
@Override
public void parseRLP() {
/** The hash from the block of which parent hash to start sending */
private byte[] hash;
/** The maximum number of blocks to return. Note: the peer could return fewer. */
private int maxBlocks;
public GetBlockHashesMessage(byte[] encoded) {
super(encoded);
}
public GetBlockHashesMessage(byte[] hash, int maxBlocks) {
this.hash = hash;
this.maxBlocks = maxBlocks;
this.parsed = true;
this.encode();
}
private void encode() {
byte[] command = RLP.encodeByte(this.getCommand().asByte());
byte[] hash = RLP.encodeElement(this.hash);
byte[] maxBlocks = RLP.encodeInt(this.maxBlocks);
this.encoded = RLP.encodeList(command, hash, maxBlocks);
}
public void parse() {
RLPList paramsList = (RLPList) RLP.decode2(encoded).get(0);
this.hash = ((RLPItem) paramsList.get(1)).getRLPData();
byte[] maxBlocksBytes = ((RLPItem) paramsList.get(2)).getRLPData();
this.maxBlocks = new BigInteger(1, maxBlocksBytes).intValue();
this.parsed = true;
}
@Override
public byte[] getPayload() {
return null;
public byte[] getEncoded() {
return encoded;
}
@Override
public String getMessageName() {
return "GetBlockHashes";
public Command getCommand() {
return GET_BLOCK_HASHES;
}
@Override
@ -21,4 +59,19 @@ public class GetBlockHashesMessage extends Message {
return BlockHashesMessage.class;
}
public byte[] getHash() {
if (!parsed) parse();
return hash;
}
public int getMaxBlocks() {
if (!parsed) parse();
return maxBlocks;
}
@Override
public String toString() {
return "[command=" + this.getCommand().name() + "]"; //TODO
}
}

View File

@ -14,19 +14,19 @@ import org.spongycastle.util.encoders.Hex;
public class GetBlocksMessage extends Message {
private List<byte[]> blockHashList = new ArrayList<byte[]>();
private List<byte[]> blockHashList = new ArrayList<>();
private BigInteger blockNum;
public GetBlocksMessage(RLPList rawData) {
super(rawData);
public GetBlocksMessage(byte[] encoded) {
super(encoded);
}
// TODO: it get's byte for now change it to int
// TODO: it get's byte for now. change it to int
public GetBlocksMessage(byte number , byte[]... blockHashList) {
byte[][] encodedElements = new byte[blockHashList.length + 2][];
encodedElements[0] = new byte[]{0x14};
encodedElements[0] = new byte[]{GET_BLOCKS.asByte()};
int i = 1;
for (byte[] hash : blockHashList) {
this.blockHashList.add(hash);
@ -36,16 +36,15 @@ public class GetBlocksMessage extends Message {
}
encodedElements[i] = RLP.encodeByte(number);
this.payload = RLP.encodeList(encodedElements);
this.encoded = RLP.encodeList(encodedElements);
this.parsed = true;
}
@Override
public void parseRLP() {
RLPList paramsList = (RLPList) rawData.get(0);
public void parse() {
RLPList paramsList = (RLPList) RLP.decode2(encoded).get(0);
if (Command.fromInt(((RLPItem) (paramsList).get(0)).getRLPData()[0]) != GET_BLOCKS)
throw new Error("GetBlocks: parsing for mal data");
if ( (((RLPItem)(paramsList).get(0)).getRLPData()[0] & 0xFF) != GET_BLOCKS.asByte())
throw new RuntimeException("Not a GetBlockssMessage command");
int size = paramsList.size();
for (int i = 1; i < size - 1; ++i) {
@ -57,17 +56,16 @@ public class GetBlocksMessage extends Message {
this.blockNum = new BigInteger(blockNumB);
this.parsed = true;
// TODO: what to do when mal data ?
}
@Override
public byte[] getPayload() {
return payload;
public byte[] getEncoded() {
return encoded;
}
@Override
public String getMessageName() {
return "GetBlocks";
public Command getCommand() {
return GET_BLOCKS;
}
@Override
@ -76,12 +74,13 @@ public class GetBlocksMessage extends Message {
}
public String toString() {
if (!parsed) parseRLP();
if (!parsed) parse();
StringBuffer sb = new StringBuffer();
for (byte[] blockHash : blockHashList)
sb.append("").append(Hex.toHexString(blockHash)).append(", ");
for (byte[] blockHash : blockHashList) {
sb.append("").append(Hex.toHexString(blockHash)).append("\n ");
}
sb.append(" blockNum=").append(blockNum);
return "GetBlocks Message [" + sb.toString() + " ]";
return "[command=" + this.getCommand().name() + " " + sb.toString() + " ]";
}
}

View File

@ -1,5 +1,8 @@
package org.ethereum.net.message;
import static org.ethereum.net.Command.GET_PEERS;
import org.ethereum.net.Command;
import org.spongycastle.util.encoders.Hex;
/**
@ -9,26 +12,27 @@ import org.spongycastle.util.encoders.Hex;
*/
public class GetPeersMessage extends Message {
public GetPeersMessage() {
this.payload = Hex.decode("C110");
/** GetPeers message is always a the same single command payload */
private final static byte[] FIXED_PAYLOAD = Hex.decode("C104");
@Override
public byte[] getEncoded() {
return FIXED_PAYLOAD;
}
@Override
public void parseRLP() {
}
public byte[] getPayload() {
return payload;
}
@Override
public String getMessageName(){
return "GetPeers";
public Command getCommand(){
return GET_PEERS;
}
@Override
public Class<PeersMessage> getAnswerMessage() {
return PeersMessage.class;
}
@Override
public String toString() {
return "[command=" + this.getCommand().name() + "]";
}
}

View File

@ -1,5 +1,8 @@
package org.ethereum.net.message;
import static org.ethereum.net.Command.GET_TRANSACTIONS;
import org.ethereum.net.Command;
import org.spongycastle.util.encoders.Hex;
/**
@ -9,26 +12,26 @@ import org.spongycastle.util.encoders.Hex;
*/
public class GetTransactionsMessage extends Message {
public GetTransactionsMessage() {
this.payload = Hex.decode("C116");
/** GetTransactions message is always a the same single command payload */
private static byte[] FIXED_PAYLOAD = Hex.decode("C116");
public byte[] getEncoded() {
return FIXED_PAYLOAD;
}
@Override
public void parseRLP() {
}
public byte[] getPayload() {
return payload;
public Command getCommand() {
return GET_TRANSACTIONS;
}
@Override
public String getMessageName(){
return "GetTransactions";
public Class<TransactionsMessage> getAnswerMessage() {
return TransactionsMessage.class;
}
@Override
public Class getAnswerMessage() {
return null;
public String toString() {
return "[command=" + this.getCommand().name() + "]";
}
}

View File

@ -1,15 +1,19 @@
package org.ethereum.net.message;
import org.spongycastle.util.encoders.Hex;
import static org.ethereum.net.Command.HELLO;
import static org.ethereum.util.ByteUtil.EMPTY_BYTE_ARRAY;
import org.ethereum.net.Command;
import org.ethereum.util.RLP;
import org.ethereum.util.RLPItem;
import org.ethereum.util.RLPList;
import org.spongycastle.util.encoders.Hex;
import com.google.common.base.Joiner;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.List;
/**
* Wrapper around an Ethereum HelloMessage on the network
@ -26,18 +30,18 @@ public class HelloMessage extends Message {
private String clientId;
/** A peer-network capability code, readable ASCII and 3 letters.
* Currently only "eth" and "shh" are known. */
private byte capabilities;
private List<String> capabilities;
/** The port on which the peer is listening for an incoming connection */
private short listenPort;
/** The identity and public key of the peer */
private byte[] peerId;
public HelloMessage(RLPList rawData) {
super(rawData);
public HelloMessage(byte[] encoded) {
super(encoded);
}
public HelloMessage(byte p2pVersion, String clientId,
byte capabilities, short listenPort, byte[] peerId) {
List<String> capabilities, short listenPort, byte[] peerId) {
this.p2pVersion = p2pVersion;
this.clientId = clientId;
this.capabilities = capabilities;
@ -46,22 +50,27 @@ public class HelloMessage extends Message {
this.parsed = true;
}
@Override
public void parseRLP() {
public void parse() {
RLPList paramsList = (RLPList) rawData.get(0);
RLPList paramsList = (RLPList) RLP.decode2(encoded).get(0);
// the message does no distinguish between the 0 and null so here I check command code for null
// TODO: find out if it can be 00
// TODO: find out if it can be 00. Do we need to check for this?
// The message does not distinguish between 0 and null,
// so we check command code for null.
if (((RLPItem) paramsList.get(0)).getRLPData() != null)
throw new Error("HelloMessage: parsing for mal data");
this.p2pVersion = ((RLPItem) paramsList.get(1)).getRLPData()[0];
byte[] p2pVersionBytes = ((RLPItem) paramsList.get(1)).getRLPData();
this.p2pVersion = p2pVersionBytes != null ? p2pVersionBytes[0] : 0;
byte[] clientIdBytes = ((RLPItem) paramsList.get(2)).getRLPData();
this.clientId = new String(clientIdBytes != null ? clientIdBytes : EMPTY_BYTE_ARRAY);
this.capabilities = ((RLPItem) paramsList.get(3)).getRLPData()[0];
RLPList capabilityList = (RLPList) paramsList.get(3);
this.capabilities = new ArrayList<>();
for (int i = 0; i < capabilityList.size(); i++) {
this.capabilities.add(new String(capabilityList.get(i).getRLPData()));
}
byte[] peerPortBytes = ((RLPItem) paramsList.get(4)).getRLPData();
this.listenPort = new BigInteger(peerPortBytes).shortValue();
@ -69,57 +78,58 @@ public class HelloMessage extends Message {
this.peerId = ((RLPItem) paramsList.get(5)).getRLPData();
this.parsed = true;
// TODO: what to do when mal data ?
}
public byte[] getPayload() {
@Override
public byte[] getEncoded() {
if (encoded == null) this.encode();
return encoded;
}
private void encode() {
byte[] command = RLP.encodeByte(HELLO.asByte());
byte[] protocolVersion = RLP.encodeByte(this.p2pVersion);
byte[] p2pVersion = RLP.encodeByte(this.p2pVersion);
byte[] clientId = RLP.encodeString(this.clientId);
byte[] capabilities = RLP.encodeByte(this.capabilities);
byte[][] capabilities = new byte[this.capabilities.size()][];
for (int i = 0; i < this.capabilities.size(); i++) {
capabilities[i] = RLP.encode(this.capabilities.get(i).getBytes());
}
byte[] capabilityList = RLP.encodeList(capabilities);
byte[] peerPort = RLP.encodeShort(this.listenPort);
byte[] peerId = RLP.encodeElement(this.peerId);
byte[] data = RLP.encodeList(command, protocolVersion,
clientId, capabilities, peerPort, peerId);
return data;
}
public byte getCommandCode() {
if (!parsed) parseRLP();
return HELLO.asByte();
this.encoded = RLP.encodeList(command, p2pVersion,
clientId, capabilityList, peerPort, peerId);
}
public byte getP2PVersion() {
if (!parsed) parseRLP();
if (!parsed) parse();
return p2pVersion;
}
public String getClientId() {
if (!parsed) parseRLP();
if (!parsed) parse();
return clientId;
}
public byte getCapabilities() {
if (!parsed) parseRLP();
public List<String> getCapabilities() {
if (!parsed) parse();
return capabilities;
}
public short getListenPort() {
if (!parsed) parseRLP();
if (!parsed) parse();
return listenPort;
}
public byte[] getPeerId() {
if (!parsed) parseRLP();
if (!parsed) parse();
return peerId;
}
@Override
public String getMessageName() {
return "HelloMessage";
public Command getCommand() {
return HELLO;
}
@Override
@ -128,14 +138,13 @@ public class HelloMessage extends Message {
}
public String toString() {
if (!parsed) parseRLP();
return "Hello Message [ command=" + HELLO.asByte() + " " +
" p2pVersion=" + this.p2pVersion + " " +
" clientId=" + this.clientId + " " +
" capabilities=" + this.capabilities + " " +
if (!parsed) parse();
return "[command=" + this.getCommand().name() +
" p2pVersion=" + this.p2pVersion +
" clientId=" + this.clientId +
" capabilities=[" + Joiner.on(" ").join(this.capabilities) + "]" +
" peerPort=" + this.listenPort + " " +
" peerId=" + Hex.toHexString(this.peerId) + " " +
"]";
}
}

View File

@ -1,30 +1,41 @@
package org.ethereum.net.message;
import org.ethereum.util.RLPList;
import org.ethereum.net.Command;
/**
* Abstract message class for all messages on the Ethereum network
*
* www.ethereumJ.com
* @author: Roman Mandeleil
* Created on: 06/04/14 14:58
*/
public abstract class Message {
RLPList rawData;
boolean parsed = false;
byte[] payload;
protected boolean parsed;
protected byte[] encoded;
public Message() {}
public Message(RLPList rawData) {
this.rawData = rawData;
public Message(byte[] encoded) {
this.encoded = encoded;
parsed = false;
}
public abstract void parseRLP();
public abstract Command getCommand();
public abstract byte[] getPayload();
public abstract String getMessageName();
/**
* Gets the RLP encoded byte array of this message
*
* @return RLP encoded byte array representation of this message
*/
public abstract byte[] getEncoded();
public abstract Class<?> getAnswerMessage();
/**
* Returns the message in String format
*
* @return A string with all attributes of the message
*/
public abstract String toString();
}

View File

@ -3,11 +3,13 @@ package org.ethereum.net.message;
import static org.ethereum.net.Command.PEERS;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import org.ethereum.net.Command;
import org.ethereum.net.client.PeerData;
import org.ethereum.net.client.Peer;
import org.ethereum.util.RLP;
import org.ethereum.util.RLPItem;
import org.ethereum.util.RLPList;
@ -21,26 +23,23 @@ public class PeersMessage extends Message {
private boolean parsed = false;
private final Set<PeerData> peers = new LinkedHashSet<PeerData>();
private Set<Peer> peers = new LinkedHashSet<>();
public PeersMessage(byte[] payload) {
super(RLP.decode2(payload));
this.payload = payload;
super(payload);
}
public PeersMessage(RLPList rawData) {
this.rawData = rawData;
parsed = false;
public PeersMessage(Set<Peer> peers) {
this.peers = peers;
this.parsed = true;
}
@Override
public void parseRLP() {
public void parse() {
RLPList paramsList = (RLPList) rawData.get(0);
RLPList paramsList = (RLPList) RLP.decode2(encoded).get(0);
if (Command.fromInt(((RLPItem)(paramsList).get(0)).getRLPData()[0] & 0xFF) != PEERS) {
throw new Error("PeersMessage: parsing for mal data");
}
if ( (((RLPItem)(paramsList).get(0)).getRLPData()[0] & 0xFF) != PEERS.asByte())
throw new RuntimeException("Not a PeersMessage command");
for (int i = 1; i < paramsList.size(); ++i) {
@ -55,42 +54,51 @@ public class PeersMessage extends Message {
peerPort = bb.getShort();
}
byte[] peerId = ((RLPItem) peerParams.get(2)).getRLPData();
PeerData peer = new PeerData(ip, peerPort, peerId);
Peer peer = new Peer(ip, peerPort, peerId);
peers.add(peer);
}
this.parsed = true;
// TODO: what to do when mal data ?
}
@Override
public byte[] getPayload() {
return payload;
public Command getCommand() {
return PEERS;
}
public Set<PeerData> getPeers() {
if (!parsed)
parseRLP();
@Override
public byte[] getEncoded() {
if (encoded == null) this.encode();
return encoded;
}
private void encode() {
byte[][] encodedByteArrays = new byte[this.peers.size()+1][];
encodedByteArrays[0] = RLP.encodeByte(this.getCommand().asByte());
List<Peer> peerList = new ArrayList<>();
peerList.addAll(this.peers);
for (int i = 0; i < peerList.size(); i++) {
encodedByteArrays[i+1] = peerList.get(i).getEncoded();
}
this.encoded = RLP.encodeList(encodedByteArrays);
}
public Set<Peer> getPeers() {
if (!parsed) this.parse();
return peers;
}
@Override
public String getMessageName() {
return "Peers";
}
@Override
public Class getAnswerMessage() {
public Class<?> getAnswerMessage() {
return null;
}
public String toString() {
if (!parsed)
parseRLP();
if (!parsed) this.parse();
StringBuffer sb = new StringBuffer();
for (PeerData peerData : peers) {
sb.append("[").append(peerData).append("] \n ");
for (Peer peerData : peers) {
sb.append("\n [").append(peerData).append("]");
}
return "Peers Message [\n " + sb.toString() + "]";
return "[command=" + this.getCommand().name() + sb.toString() + "]";
}
}

View File

@ -1,5 +1,8 @@
package org.ethereum.net.message;
import static org.ethereum.net.Command.PING;
import org.ethereum.net.Command;
import org.spongycastle.util.encoders.Hex;
/**
@ -9,26 +12,25 @@ import org.spongycastle.util.encoders.Hex;
*/
public class PingMessage extends Message {
public PingMessage() {
this.payload = Hex.decode("C102");
/** Ping message is always a the same single command payload */
private static byte[] FIXED_PAYLOAD = Hex.decode("C102");
public byte[] getEncoded() {
return FIXED_PAYLOAD;
}
@Override
public void parseRLP() {
}
public byte[] getPayload() {
return payload;
}
@Override
public String getMessageName(){
return "Ping";
public Command getCommand() {
return PING;
}
@Override
public Class<PongMessage> getAnswerMessage() {
return PongMessage.class;
}
}
@Override
public String toString() {
return "[command=" + getCommand().name() + "]";
}
}

View File

@ -1,5 +1,8 @@
package org.ethereum.net.message;
import static org.ethereum.net.Command.PONG;
import org.ethereum.net.Command;
import org.spongycastle.util.encoders.Hex;
/**
@ -9,25 +12,26 @@ import org.spongycastle.util.encoders.Hex;
*/
public class PongMessage extends Message {
public PongMessage() {
this.payload = Hex.decode("C103");
/** Pong message is always a the same single command payload */
private static byte[] FIXED_PAYLOAD = Hex.decode("C103");
@Override
public byte[] getEncoded() {
return FIXED_PAYLOAD;
}
@Override
public void parseRLP() {
}
public byte[] getPayload() {
return payload;
}
public String getMessageName(){
return "Pong";
public Command getCommand() {
return PONG;
}
@Override
public Class getAnswerMessage() {
public Class<?> getAnswerMessage() {
return null;
}
}
@Override
public String toString() {
return "[command=PONG]";
}
}

View File

@ -22,7 +22,7 @@ public enum ReasonCode {
private int reason;
private static final Map<Integer, ReasonCode> intToTypeMap = new HashMap<Integer, ReasonCode>();
private static final Map<Integer, ReasonCode> intToTypeMap = new HashMap<>();
static {
for (ReasonCode type : ReasonCode.values()) {
intToTypeMap.put(type.reason, type);

View File

@ -1,5 +1,9 @@
package org.ethereum.net.message;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.ethereum.config.SystemProperties;
import org.ethereum.core.Genesis;
import org.ethereum.crypto.HashUtil;
@ -18,31 +22,31 @@ public class StaticMessages {
public final static GetPeersMessage GET_PEERS_MESSAGE = new GetPeersMessage();
public final static GetTransactionsMessage GET_TRANSACTIONS_MESSAGE = new GetTransactionsMessage();
public static final byte[] PING_PACKET = Hex.decode("2240089100000002C102");
public static final byte[] PONG_PACKET = Hex.decode("2240089100000002C103");
public static final byte[] GET_PEERS_PACKET = Hex.decode("2240089100000002C110");
public static final byte[] GET_TRANSACTIONS = Hex.decode("2240089100000002C116");
public static final byte[] DISCONNECT_08 = Hex.decode("2240089100000003C20108");
public static final byte[] DISCONNECT_PEER_QUITTING = Hex.decode("2240089100000003C20108");
public static final byte[] SYNC_TOKEN = Hex.decode("22400891");
public static final byte[] GENESIS_HASH = Genesis.getInstance().getHash();
private static HelloMessage generateHelloMessage() {
String helloAnnouncement = buildHelloAnnouncement();
byte p2pVersion = 0x00;
List<String> capabilities = new ArrayList<>(Arrays.asList("eth"));
short listenPort = (short) 30303;
byte[] peerIdBytes = HashUtil.randomPeerId();
return new HelloMessage(p2pVersion, helloAnnouncement,
capabilities, listenPort, peerIdBytes);
}
private static String buildHelloAnnouncement() {
String version = SystemProperties.CONFIG.projectVersion();
String system = System.getProperty("os.name");
if (system.contains(" "))
system = system.substring(0, system.indexOf(" "));
if (System.getProperty("java.vm.vendor").contains("Android"))
system = "Android";
String phrase = SystemProperties.CONFIG.helloPhrase();
String helloAnnouncement = String.format("Ethereum(J)/v%s/%s/%s/Java", version, phrase, system);
return new HelloMessage((byte) 0x21, helloAnnouncement,
Byte.parseByte("00000111", 2), (short) 30303, peerIdBytes);
return String.format("Ethereum(J)/v%s/%s/%s/Java", version, phrase, system);
}
}

View File

@ -2,9 +2,12 @@ package org.ethereum.net.message;
import static org.ethereum.net.Command.STATUS;
import org.ethereum.net.Command;
import org.ethereum.util.ByteUtil;
import org.ethereum.util.RLP;
import org.ethereum.util.RLPItem;
import org.ethereum.util.RLPList;
import org.spongycastle.util.encoders.Hex;
/**
* Wrapper around an Ethereum StatusMessage on the network
@ -23,8 +26,8 @@ public class StatusMessage extends Message {
/** The hash of the Genesis block */
private byte[] genesisHash;
public StatusMessage(RLPList rawData) {
super(rawData);
public StatusMessage(byte[] encoded) {
super(encoded);
}
public StatusMessage(byte protocolVersion, byte networkId,
@ -35,18 +38,18 @@ public class StatusMessage extends Message {
this.bestHash = bestHash;
this.genesisHash = genesisHash;
this.parsed = true;
this.encode();
}
@Override
public void parseRLP() {
public void parse() {
RLPList paramsList = (RLPList) rawData.get(0);
RLPList paramsList = (RLPList) RLP.decode2(encoded).get(0);
/* the message does not distinguish between the 0 and null
* so check command code for null */
// TODO: find out if it can be 00
if (((RLPItem) paramsList.get(0)).getRLPData() != null)
throw new Error("StaticMessage: parsing for mal data");
if ( (((RLPItem)(paramsList).get(0)).getRLPData()[0] & 0xFF) != STATUS.asByte())
throw new RuntimeException("Not a StatusMessage command");
this.protocolVersion = ((RLPItem) paramsList.get(1)).getRLPData()[0];
byte[] networkIdBytes = ((RLPItem) paramsList.get(2)).getRLPData();
@ -59,7 +62,12 @@ public class StatusMessage extends Message {
}
@Override
public byte[] getPayload() {
public byte[] getEncoded() {
if (encoded == null) this.encode();
return encoded;
}
private void encode() {
byte[] command = RLP.encodeByte(STATUS.asByte());
byte[] protocolVersion = RLP.encodeByte(this.protocolVersion);
byte[] networkId = RLP.encodeByte(this.networkId);
@ -67,19 +75,54 @@ public class StatusMessage extends Message {
byte[] bestHash = RLP.encodeElement(this.bestHash);
byte[] genesisHash = RLP.encodeElement(this.genesisHash);
byte[] data = RLP.encodeList(command, protocolVersion, networkId,
this.encoded = RLP.encodeList(command, protocolVersion, networkId,
totalDifficulty, bestHash, genesisHash);
return data;
}
@Override
public String getMessageName() {
return "StatusMessage";
public Command getCommand() {
return STATUS;
}
@Override
public Class<?> getAnswerMessage() {
return null;
}
public byte getProtocolVersion() {
if (!parsed) this.parse();
return protocolVersion;
}
public byte getNetworkId() {
if (!parsed) this.parse();
return networkId;
}
public byte[] getTotalDifficulty() {
if (!parsed) this.parse();
return totalDifficulty;
}
public byte[] getBestHash() {
if (!parsed) this.parse();
return bestHash;
}
public byte[] getGenesisHash() {
if (!parsed) this.parse();
return genesisHash;
}
@Override
public String toString() {
if (!parsed) parse();
return "[command=" + this.getCommand().name() +
" protocolVersion=" + this.protocolVersion +
" networkId=" + this.networkId +
" totalDifficulty=" + ByteUtil.toHexString(this.totalDifficulty) +
" bestHash=" + Hex.toHexString(this.bestHash) + " " +
" genesisHash=" + Hex.toHexString(this.genesisHash) + " " +
"]";
}
}

View File

@ -7,11 +7,7 @@ import org.ethereum.net.Command;
import org.ethereum.util.RLP;
import org.ethereum.util.RLPItem;
import org.ethereum.util.RLPList;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
@ -22,52 +18,39 @@ import java.util.List;
*/
public class TransactionsMessage extends Message {
private Logger logger = LoggerFactory.getLogger("wire");
private List<Transaction> transactions = new ArrayList<Transaction>();
private List<Transaction> transactions = new ArrayList<>();
public TransactionsMessage() {
public TransactionsMessage(byte[] encoded) {
super(encoded);
}
public TransactionsMessage(List<Transaction> transactionList) {
this.transactions = transactionList;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
for (Transaction tx : transactionList) {
byte[] txPayload = tx.getEncoded();
try {
baos.write(txPayload);
} catch (IOException e) {
logger.error(e.getMessage(), e);
}
}
byte[][] elements = new byte[transactionList.size() + 1][];
elements[0] = new byte[]{Command.TRANSACTIONS.asByte()};
for (int i = 0; i < transactionList.size(); ++i)
elements[i + 1] = transactionList.get(i).getEncoded();
payload = RLP.encodeList(elements);
}
public TransactionsMessage(byte[] payload) {
super(RLP.decode2(payload));
this.payload = payload;
}
public TransactionsMessage(RLPList rawData) {
this.rawData = rawData;
parsed = false;
}
@Override
public void parseRLP() {
RLPList paramsList = (RLPList) rawData.get(0);
public byte[] getEncoded() {
if (encoded == null) this.encode();
return encoded;
}
if (Command.fromInt(((RLPItem) (paramsList).get(0)).getRLPData()[0] & 0xFF) != TRANSACTIONS)
throw new Error("TransactionMessage: parsing for mal data");
private void encode() {
byte[][] encodedTransactions = new byte[transactions.size()][];
byte[] command = new byte[]{Command.TRANSACTIONS.asByte()};
for (int i = 0; i < transactions.size(); ++i)
encodedTransactions[i + 1] = transactions.get(i).getEncoded();
byte[] encodedTxsList = RLP.encodeList(encodedTransactions);
this.encoded = RLP.encodeList(command, encodedTxsList);
}
transactions = new ArrayList<Transaction>();
private void parse() {
RLPList paramsList = (RLPList) RLP.decode2(encoded).get(0);
int commandByte = ((RLPItem) (paramsList).get(0)).getRLPData()[0] & 0xFF;
if (Command.fromInt(commandByte) != TRANSACTIONS)
throw new RuntimeException("Not a TransactionMessage: " + Integer.toHexString(commandByte));
transactions = new ArrayList<>();
int size = paramsList.size();
for (int i = 1; i < size; ++i) {
RLPList rlpTxData = (RLPList) paramsList.get(i);
@ -78,27 +61,22 @@ public class TransactionsMessage extends Message {
}
public List<Transaction> getTransactions() {
if (!parsed) parseRLP();
if (!parsed) parse();
return transactions;
}
@Override
public String getMessageName() {
return "Transactions";
public Command getCommand() {
return TRANSACTIONS;
}
@Override
public Class getAnswerMessage() {
public Class<?> getAnswerMessage() {
return null;
}
@Override
public byte[] getPayload() {
return payload;
}
public String toString() {
if(!parsed) parseRLP();
if(!parsed) parse();
StringBuffer sb = new StringBuffer();
for (Transaction transaction : transactions)
sb.append(" ").append(transaction).append("\n");

View File

@ -1,178 +0,0 @@
package org.ethereum.net.peerdiscovery;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.ChannelOption;
import io.netty.channel.FixedRecvByteBufAllocator;
import org.ethereum.manager.WorldManager;
import org.ethereum.net.Command;
import org.ethereum.net.PeerListener;
import org.ethereum.net.message.DisconnectMessage;
import org.ethereum.net.message.HelloMessage;
import org.ethereum.net.message.PeersMessage;
import org.ethereum.net.message.StaticMessages;
import org.ethereum.util.ByteUtil;
import org.ethereum.util.RLP;
import org.ethereum.util.RLPList;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.spongycastle.util.encoders.Hex;
import static org.ethereum.net.Command.*;
/**
* www.ethereumJ.com
* @author: Roman Mandeleil
* Created on: 10/04/14 08:19
*/
public class EthereumPeerTasterHandler extends ChannelInboundHandlerAdapter {
private final static Logger logger = LoggerFactory.getLogger("peerdiscovery");
private final static byte[] MAGIC_PREFIX = {(byte)0x22, (byte)0x40, (byte)0x08, (byte)0x91};
private long lastPongTime = 0;
private boolean tearDown = false;
private PeerListener peerListener;
private HelloMessage handshake = null;
public EthereumPeerTasterHandler() { }
public EthereumPeerTasterHandler(PeerListener peerListener) {
this.peerListener = peerListener;
}
@Override
public void channelActive(final ChannelHandlerContext ctx) {
// Here we send the hello message with random id each time
// to not interrupt active peer
HelloMessage helloMessage = StaticMessages.HELLO_MESSAGE;
byte[] helloLength =ByteUtil.calcPacketLength(helloMessage.getPayload());
final ByteBuf buffer = ctx.alloc().buffer(helloMessage.getPayload().length + 8);
buffer.writeBytes(MAGIC_PREFIX);
buffer.writeBytes(helloLength);
buffer.writeBytes(helloMessage.getPayload());
logger.info("Send: " + helloMessage.toString());
ctx.writeAndFlush(buffer);
}
@Override
public void channelRead(final ChannelHandlerContext ctx, Object msg) throws Exception {
byte[] payload = (byte[]) msg;
logger.info("[Send msg: [{}] ]", Hex.toHexString(payload));
byte command = RLP.getCommandCode(payload);
// got HELLO
if (Command.fromInt(command) == HELLO) {
logger.info("[Recv: HELLO]" );
RLPList rlpList = RLP.decode2(payload);
HelloMessage helloMessage = new HelloMessage(rlpList);
handshake = helloMessage;
logger.info(helloMessage.toString());
sendGetPeers(ctx);
}
// got DISCONNECT
if (Command.fromInt(command) == DISCONNECT) {
logger.info("[Recv: DISCONNECT]");
if (peerListener != null) peerListener.console("[Recv: DISCONNECT]");
RLPList rlpList = RLP.decode2(payload);
DisconnectMessage disconnectMessage = new DisconnectMessage(rlpList);
logger.info(disconnectMessage.toString());
}
// got PING send pong
if (Command.fromInt(command) == PING) {
logger.info("[Recv: PING]");
if (peerListener != null) peerListener.console("[Recv: PING]");
sendPong(ctx);
}
// got PONG mark it
if (Command.fromInt(command) == PONG) {
logger.info("[Recv: PONG]" );
if (peerListener != null) peerListener.console("[Recv: PONG]");
this.lastPongTime = System.currentTimeMillis();
}
// got PEERS
if (Command.fromInt(command) == PEERS) {
logger.info("[Recv: PEERS]");
if (peerListener != null) peerListener.console("[Recv: PEERS]");
RLPList rlpList = RLP.decode2(payload);
PeersMessage peersMessage = new PeersMessage(rlpList);
WorldManager.getInstance().addPeers(peersMessage.getPeers());
logger.info(peersMessage.toString());
sendDisconnectNice(ctx);
ctx.close().sync();
ctx.disconnect().sync();
}
}
@Override
public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
// limit the size of recieving buffer to 1024
ctx.channel().config().setRecvByteBufAllocator(new FixedRecvByteBufAllocator(32368));
ctx.channel().config().setOption(ChannelOption.SO_RCVBUF, 32368);
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
this.tearDown = true;
logger.info("Lost connection to the server");
logger.error(cause.getMessage(), cause);
ctx.close().sync();
ctx.disconnect().sync();
}
private void sendPing(ChannelHandlerContext ctx) {
ByteBuf buffer = ctx.alloc().buffer(StaticMessages.PING_PACKET.length);
buffer.writeBytes(StaticMessages.PING_PACKET);
ctx.writeAndFlush(buffer);
}
private void sendPong(ChannelHandlerContext ctx) {
logger.info("[Send: PONG]");
ByteBuf buffer = ctx.alloc().buffer(StaticMessages.PONG_PACKET.length);
buffer.writeBytes(StaticMessages.PONG_PACKET);
ctx.writeAndFlush(buffer);
}
private void sendDisconnectNice(ChannelHandlerContext ctx) {
logger.info("[Send: DISCONNECT]");
ByteBuf buffer = ctx.alloc().buffer(StaticMessages.DISCONNECT_08.length);
buffer.writeBytes(StaticMessages.DISCONNECT_08);
ctx.writeAndFlush(buffer);
}
private void sendGetPeers(ChannelHandlerContext ctx) {
ByteBuf buffer = ctx.alloc().buffer(StaticMessages.GET_PEERS_PACKET.length);
buffer.writeBytes(StaticMessages.GET_PEERS_PACKET);
ctx.writeAndFlush(buffer);
}
public HelloMessage getHandshake(){
return this.handshake;
}
}

View File

@ -1,6 +1,6 @@
package org.ethereum.net.peerdiscovery;
import org.ethereum.net.client.PeerData;
import org.ethereum.net.client.Peer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -24,11 +24,11 @@ public class PeerDiscovery {
private ThreadPoolExecutor executorPool;
private PeerDiscoveryMonitorThread monitor;
private final Set<PeerData> peers;
private final Set<Peer> peers;
private final AtomicBoolean started = new AtomicBoolean(false);
public PeerDiscovery(Set<PeerData> peers) {
public PeerDiscovery(Set<Peer> peers) {
this.peers = peers;
}
@ -49,14 +49,14 @@ public class PeerDiscovery {
Thread monitorThread = new Thread(monitor);
monitorThread.start();
for (PeerData peerData : this.peers) {
for (Peer peerData : this.peers) {
executorPool.execute(new WorkerThread(peerData, executorPool));
}
started.set(true);
}
public void addNewPeerData(PeerData peerData) {
public void addNewPeerData(Peer peerData) {
logger.debug("add new peer for discovery: {}", peerData);
executorPool.execute(new WorkerThread(peerData, executorPool));
}

View File

@ -20,7 +20,7 @@ import org.ethereum.manager.WorldManager;
import org.ethereum.net.Command;
import org.ethereum.net.MessageQueue;
import org.ethereum.net.PeerListener;
import org.ethereum.net.client.PeerData;
import org.ethereum.net.client.Peer;
import org.ethereum.net.message.DisconnectMessage;
import org.ethereum.net.message.HelloMessage;
import org.ethereum.net.message.Message;
@ -194,7 +194,7 @@ public class PeerProtocolHandler extends ChannelInboundHandlerAdapter {
}
protected void sendPeers() {
Set<PeerData> peers = WorldManager.getInstance().getPeers();
Set<Peer> peers = WorldManager.getInstance().getPeers();
PeersMessage peersMessage = new PeersMessage(peers);
sendMsg(peersMessage);
}

View File

@ -20,10 +20,7 @@ import static org.ethereum.config.SystemProperties.CONFIG;
public class PeerTaster {
private final static Logger logger = LoggerFactory.getLogger("peerdiscovery");
final EthereumPeerTasterHandler handler = new EthereumPeerTasterHandler();
public PeerTaster() {
}
private final PeerProtocolHandler handler = new PeerProtocolHandler();
public void connect(String host, int port) {
@ -34,7 +31,6 @@ public class PeerTaster {
Bootstrap b = new Bootstrap();
b.group(workerGroup);
b.channel(NioSocketChannel.class);
b.handler(new ChannelInitializer<NioSocketChannel>() {
@Override
public void initChannel(NioSocketChannel ch) throws Exception {
@ -43,14 +39,14 @@ public class PeerTaster {
ch.pipeline().addLast(handler);
}
});
b.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, CONFIG.peerDiscoveryTimeout());
// Start the client.
b.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, CONFIG.peerDiscoveryTimeout());
ChannelFuture f = b.connect(host, port).sync(); // (5)
// Wait until the connection is closed.
f.channel().closeFuture().sync();
logger.debug("connection is closed");
logger.debug("Connection is closed");
} catch (InterruptedException ie) {
logger.info("-- ClientPeer: catch (InterruptedException ie) --");
@ -66,5 +62,4 @@ public class PeerTaster {
public HelloMessage getHandshake() {
return handler.getHandshake();
}
}

View File

@ -1,6 +1,6 @@
package org.ethereum.net.peerdiscovery;
import org.ethereum.net.client.PeerData;
import org.ethereum.net.client.Peer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -16,28 +16,26 @@ public class WorkerThread implements Runnable {
private final static Logger logger = LoggerFactory.getLogger("peerdiscovery");
ThreadPoolExecutor poolExecutor;
private PeerData peerData;
private Peer peerData;
private PeerTaster peerTaster;
public WorkerThread(PeerData peerData, ThreadPoolExecutor poolExecutor) {
public WorkerThread(Peer peerData, ThreadPoolExecutor poolExecutor) {
this.poolExecutor = poolExecutor;
this.peerData = peerData;
}
@Override
public void run() {
logger.info(Thread.currentThread().getName()+" Start. Command = "+ peerData.toString());
logger.info("{} start", Thread.currentThread().getName());
processCommand();
logger.info(Thread.currentThread().getName()+" End.");
logger.info("{} end", Thread.currentThread().getName());
try {Thread.sleep(10000); } catch (InterruptedException e) {logger.error("sleep interrupted");}
poolExecutor.execute(this);
}
private void processCommand() {
try {
peerTaster = new PeerTaster();
peerTaster.connect(peerData.getInetAddress().getHostAddress(), peerData.getPort());
@ -47,9 +45,8 @@ public class WorkerThread implements Runnable {
}
catch (Throwable e) {
if (peerData.isOnline() == true)
logger.info("Peer: [ {} ] got offline, due: [ {} ]",
peerData.getInetAddress().getHostAddress(),
e);
logger.info("Peer: [{}] went offline, due to: [{}]",
peerData.getInetAddress().getHostAddress(), e);
logger.info("Peer: " + peerData.toString() + " isOnline: false");
peerData.setOnline(false);
} finally {

View File

@ -12,6 +12,7 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@ -77,7 +78,7 @@ public class SerpentCompiler {
String[] lexaArr = code.split("\\s+");
List<String> lexaList = new ArrayList<String>();
List<String> lexaList = new ArrayList<>();
Collections.addAll(lexaList, lexaArr);
// Encode push_n numbers
@ -134,7 +135,7 @@ public class SerpentCompiler {
}
// calc label pos & remove labels
HashMap<String, Integer> labels = new HashMap<String, Integer>();
Map<String, Integer> labels = new HashMap<>();
for (int i = 0; i < lexaList.size(); ++i) {

View File

@ -8,6 +8,7 @@ import java.math.BigInteger;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@ -19,10 +20,10 @@ import java.util.regex.Pattern;
public class SerpentToAssemblyCompiler extends SerpentBaseVisitor<String> {
private int labelIndex = 0;
private ArrayList<String> vars = new ArrayList<String>();
private List<String> vars = new ArrayList<>();
private HashMap<String, Integer> arraysSize = new HashMap<String, Integer>();
private List<String> arraysIndex = new ArrayList<String>();
private Map<String, Integer> arraysSize = new HashMap<>();
private List<String> arraysIndex = new ArrayList<>();
@Override
public String visitParse(@NotNull SerpentParser.ParseContext ctx) {

View File

@ -133,9 +133,8 @@ public class TrieImpl implements Trie {
* @return value
*/
public byte[] get(byte[] key) {
if(logger.isDebugEnabled()) {
if (logger.isDebugEnabled())
logger.debug("Retrieving key {}", Hex.toHexString(key));
}
byte[] k = binToNibbles(key);
Value c = new Value(this.get(this.root, k));

View File

@ -22,8 +22,8 @@ public class ByteUtil {
}
/**
* The regular {@link java.math.BigInteger#toByteArray()} method isn't quite what we often need: it appends a
* leading zero to indicate that the number is positive and may need padding.
* The regular {@link java.math.BigInteger#toByteArray()} method isn't quite what we often need:
* it appends a leading zero to indicate that the number is positive and may need padding.
*
* @param b the integer to format into a byte array
* @param numBytes the desired size of the resulting byte array
@ -41,10 +41,10 @@ public class ByteUtil {
}
/**
* emitting sign indication byte
* Omitting sign indication byte
*
* @param b - any big integer number
* @return
* @return a byte array representation of this number without a sign byte
*/
public static byte[] bigIntegerToBytes(BigInteger b) {
if (b == null)
@ -84,7 +84,7 @@ public class ByteUtil {
}
public static String toHexString(byte[] data) {
if (data == null) return "null";
if (data == null) return "";
else return Hex.toHexString(data);
}
@ -129,12 +129,18 @@ public class ByteUtil {
public static String nibblesToPrettyString(byte[] nibbles){
StringBuffer buffer = new StringBuffer();
for (byte nibble : nibbles) {
String nibleString = Utils.oneByteToHexString(nibble);
String nibleString = oneByteToHexString(nibble);
buffer.append("\\x" + nibleString);
}
return buffer.toString();
}
public static String oneByteToHexString(byte value) {
String retVal = Integer.toString(value & 0xFF, 16);
if (retVal.length() == 1) retVal = "0" + retVal;
return retVal;
}
/**
* Calculate the number of bytes need
* to encode the number
@ -155,6 +161,22 @@ public class ByteUtil {
return bytes;
}
/**
* Convert an array of byte arrays to a single string
* <br/>
* Example: "eth" or "eth shh bzz"
*
* @return byte arrays as String
*/
public static String toString(byte[][] arrays) {
StringBuilder sb = new StringBuilder();
for (byte[] array : arrays) {
sb.append(new String(array)).append(" ");
}
if(sb.length() > 0) sb.deleteCharAt(sb.length()-1);
return sb.toString();
}
/**
* @param arg - not more that 32 bits
* @return - bytes of the value pad with complete to 32 zeroes

View File

@ -627,7 +627,7 @@ public class RLP {
// It's an item less than 55 bytes long,
// data[0] - 0x80 == length of the item
if ((msgData[pos] & 0xFF) > OFFSET_SHORT_ITEM
&& (msgData[pos] & 0xFF) < OFFSET_LONG_ITEM) {
&& (msgData[pos] & 0xFF) <= OFFSET_LONG_ITEM) {
byte length = (byte) ((msgData[pos] & 0xFF) - OFFSET_SHORT_ITEM);
@ -706,7 +706,7 @@ public class RLP {
}
private static DecodeResult decodeList(byte[] data, int pos, int prevPos, int len) {
List<Object> slice = new ArrayList<Object>();
List<Object> slice = new ArrayList<>();
for (int i = 0; i < len;) {
// Get the next item in the data list and append it
DecodeResult result = decode(data, pos);
@ -828,9 +828,7 @@ public class RLP {
(srcData.length == 1 && srcData[0] == 0)) {
return new byte[]{(byte) 0x80};
} if (srcData.length == 1 && (srcData[0] & 0xFF) < 0x80) {
return srcData;
} else if (srcData.length < SIZE_THRESHOLD) {
// length = 8X
byte length = (byte) (OFFSET_SHORT_ITEM + srcData.length);

View File

@ -119,13 +119,6 @@ public class Utils {
return Double.parseDouble (version.substring (0, pos - 1));
}
public static String oneByteToHexString(byte value) {
String retVal = Integer.toString(value & 0xFF, 16);
if (retVal.length() == 1) retVal = "0" + retVal;
return retVal;
}
public static String getFromUrl(String urlToRead) {
URL url;
HttpURLConnection conn;

View File

@ -263,7 +263,7 @@ public class Value {
output.append("'");
for (byte oneByte : asBytes()) {
if (oneByte < 16) {
output.append("\\x").append(Utils.oneByteToHexString(oneByte));
output.append("\\x").append(ByteUtil.oneByteToHexString(oneByte));
} else {
output.append(Character.valueOf((char)oneByte));
}
@ -278,14 +278,13 @@ public class Value {
return "Unexpected type";
}
public int countYourBranchNodes(){
public int countBranchNodes() {
if (this.isList()) {
List<Object> objList = this.asList();
int i = 0;
for (Object obj : objList) {
i += (new Value(obj)).countYourBranchNodes();
i += (new Value(obj)).countBranchNodes();
}
return i;
} else if (this.isBytes()) {

View File

@ -312,8 +312,8 @@ public enum OpCode {
private byte opcode;
private static final Map<Byte, OpCode> intToTypeMap = new HashMap<Byte, OpCode>();
private static final Map<String, Byte> stringToByteMap = new HashMap<String, Byte>();
private static final Map<Byte, OpCode> intToTypeMap = new HashMap<>();
private static final Map<String, Byte> stringToByteMap = new HashMap<>();
static {
for (OpCode type : OpCode.values()) {

View File

@ -4,7 +4,6 @@ import org.ethereum.crypto.HashUtil;
import org.ethereum.db.ContractDetails;
import org.ethereum.facade.Repository;
import org.ethereum.util.ByteUtil;
import org.ethereum.util.Utils;
import org.ethereum.vm.MessageCall.MsgType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -606,7 +605,7 @@ public class Program {
// Check if value is ASCII
String character = ((byte) 0x20 <= value && value <= (byte) 0x7e) ? new String(new byte[] { value }) : "?";
firstLine.append(character).append("");
secondLine.append(Utils.oneByteToHexString(value)).append(" ");
secondLine.append(ByteUtil.oneByteToHexString(value)).append(" ");
if ((i + 1) % 8 == 0) {
String tmp = String.format("%4s", Integer.toString(i - 7, 16)).replace(" ", "0");
@ -650,7 +649,7 @@ public class Program {
for (int i = 0; memory != null && i < memory.limit(); ++i) {
byte value = memory.get(i);
oneLine.append(Utils.oneByteToHexString(value)).append(" ");
oneLine.append(ByteUtil.oneByteToHexString(value)).append(" ");
if ((i + 1) % 16 == 0) {
String tmp = String.format("[%4s]-[%4s]", Integer.toString(i - 15, 16),

View File

@ -16,7 +16,7 @@ import org.iq80.leveldb.WriteOptions;
public class MockDB implements DB {
Map<ByteArrayWrapper, byte[]> storage = new HashMap<ByteArrayWrapper, byte[]>();
Map<ByteArrayWrapper, byte[]> storage = new HashMap<>();
@Override
public void close() throws IOException {

File diff suppressed because one or more lines are too long

View File

@ -4,8 +4,6 @@ import static org.junit.Assert.assertEquals;
import org.ethereum.net.message.DisconnectMessage;
import org.ethereum.net.message.ReasonCode;
import org.ethereum.util.RLP;
import org.ethereum.util.RLPList;
import org.junit.Test;
import org.spongycastle.util.encoders.Hex;
@ -13,27 +11,25 @@ public class DisconnectMessageTest {
/* DISCONNECT_MESSAGE */
@Test /* DisconnectMessage 1 */
public void test_3() {
@Test /* DisconnectMessage 1 - Requested */
public void test_1() {
String disconnectMessageRaw = "C20100";
byte[] payload = Hex.decode(disconnectMessageRaw);
RLPList rlpList = RLP.decode2(payload);
DisconnectMessage disconnectMessage = new DisconnectMessage(rlpList);
DisconnectMessage disconnectMessage = new DisconnectMessage(payload);
System.out.println(disconnectMessage);
assertEquals(disconnectMessage.getReason(), ReasonCode.REQUESTED);
}
@Test /* DisconnectMessage 2 */
public void test_4() {
@Test /* DisconnectMessage 2 - TCP Error */
public void test_2() {
String disconnectMessageRaw = "C20101";
byte[] payload = Hex.decode(disconnectMessageRaw);
RLPList rlpList = RLP.decode2(payload);
DisconnectMessage disconnectMessage = new DisconnectMessage(rlpList);
DisconnectMessage disconnectMessage = new DisconnectMessage(payload);
System.out.println(disconnectMessage);
assertEquals(disconnectMessage.getReason(), ReasonCode.TCP_ERROR);

View File

@ -2,9 +2,11 @@ package org.ethereum.net;
import static org.junit.Assert.assertEquals;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.ethereum.net.message.HelloMessage;
import org.ethereum.util.RLP;
import org.ethereum.util.RLPList;
import org.junit.Test;
import org.spongycastle.util.encoders.Hex;
@ -12,51 +14,76 @@ public class HelloMessageTest {
/* HELLO_MESSAGE */
@Test /* HelloMessage 1 */
public void test_1() {
@Test /* HelloMessage 1 from PeerServer */
public void testPeer() {
String helloMessageRaw = "F8 80 80 80 B7 45 74 68 " +
"65 72 65 75 6D 28 2B 2B 29 2F 50 65 65 72 20 53 " +
"65 72 76 65 72 20 5A 65 72 6F 2F 76 30 2E 36 2E " +
"38 64 2F 52 65 6C 65 61 73 65 2F 4C 69 6E 75 78 " +
"2F 67 2B 2B C0 82 76 5F B8 40 20 17 B9 5D 55 86 " +
"AD D0 53 E7 C5 DC C8 11 2D B1 D5 57 ED 83 58 9C " +
"4E 0B D2 54 42 F3 9E 41 11 65 5A 48 72 57 AA 7E " +
"4E D3 09 E8 B4 D5 5B E5 FA 8D 8D 6E 97 B7 2C 67 " +
"D7 6A A0 3E B6 9A D9 81 ED 60";
String helloMessageRaw = "F8 77 80 0C 80 AD 45 74 " +
"68 65 72 65 75 6D 28 2B 2B 29 2F 5A 65 72 6F 47 " +
"6F 78 2F 76 30 2E 35 2E 31 2F 6E 63 75 72 73 65 " +
"73 2F 4C 69 6E 75 78 2F 67 2B 2B 07 82 76 5F B8 " +
"40 D8 83 3B 83 56 0E 0B 12 17 0E 91 69 DC 43 78 " +
"42 23 A5 98 42 DE 23 59 E6 D0 3D B3 4C 30 A9 66 " +
"C2 DE 3B 4B 25 52 FB 0D 75 95 A1 85 D5 58 F2 E6 " +
"69 B5 95 67 4F 52 17 C9 96 EE 14 88 84 82 8B E0 FD";
byte[] payload = Hex.decode(helloMessageRaw);
RLPList rlpList = RLP.decode2(payload);
HelloMessage helloMessage = new HelloMessage(rlpList);
helloMessage.parseRLP();
HelloMessage helloMessage = new HelloMessage(payload);
System.out.println(helloMessage);
assertEquals(12, helloMessage.getP2PVersion());
assertEquals("Ethereum(++)/ZeroGox/v0.5.1/ncurses/Linux/g++", helloMessage.getClientId());
assertEquals(7, helloMessage.getCapabilities());
assertEquals(0, helloMessage.getP2PVersion());
assertEquals("Ethereum(++)/Peer Server Zero/v0.6.8d/Release/Linux/g++", helloMessage.getClientId());
assertEquals(0, helloMessage.getCapabilities().size());
assertEquals(30303, helloMessage.getListenPort());
assertEquals(
"D8833B83560E0B12170E9169DC43784223A59842DE2359E6D03DB34C30A966C2DE3B4B2552FB0D7595A185D558F2E669B595674F5217C996EE148884828BE0FD",
"2017B95D5586ADD053E7C5DCC8112DB1D557ED83589C4E0BD25442F39E4111655A487257AA7E4ED309E8B4D55BE5FA8D8D6E97B72C67D76AA03EB69AD981ED60",
Hex.toHexString(helloMessage.getPeerId()).toUpperCase());
}
@Test /* HelloMessage 2 */
public void test_2() {
@Test /* HelloMessage 2 from Node */
public void testNode() {
String helloMessageRaw = "F8 7B 80 80 AE 4E 45 74 68 65 72 65 "
+ "75 6D 28 2B 2B 29 2F 5A 65 72 6F 47 6F 78 2F 76 30 "
+ "2E 36 2E 39 2F 6E 63 75 72 73 65 73 2F 4C 69 6E 75 "
+ "78 2F 67 2B 2B C4 83 65 74 68 82 76 5F B8 40 CA DF "
+ "B9 3D 2B B5 FB E2 94 35 84 D9 3E D9 0E 37 46 67 C9 "
+ "E8 B2 50 2E 97 46 93 CC C6 B3 D3 70 BD 4C DE 77 38 "
+ "D0 B6 26 E3 D2 F3 CA EC C5 9E 13 02 D1 71 1B F5 95 "
+ "71 10 60 D7 B4 92 1E 18 B9 76 56";
String helloMessageRaw = "F87F800B80B5457468657265756D282B2B292F76302E342E332F4554485F4255494C445F545950452F4554485F4255494C445F504C4154464F524D0782765FB840E02B18FBA6B887FB9258469C3AF8E445CC9AE2B5386CAC5F60C4170F822086224E3876555C745A7EC8AC181C7F9701776D94A779604EA12651DE5F4A748D29E1";
byte[] payload = Hex.decode(helloMessageRaw);
RLPList rlpList = RLP.decode2(payload);
HelloMessage helloMessage = new HelloMessage(rlpList);
helloMessage.parseRLP();
HelloMessage helloMessage = new HelloMessage(payload);
helloMessage.parse();
System.out.println(helloMessage);
assertEquals(11, helloMessage.getP2PVersion());
assertEquals("Ethereum(++)/v0.4.3/ETH_BUILD_TYPE/ETH_BUILD_PLATFORM", helloMessage.getClientId());
assertEquals(7, helloMessage.getCapabilities());
assertEquals(0, helloMessage.getP2PVersion());
assertEquals("NEthereum(++)/ZeroGox/v0.6.9/ncurses/Linux/g++", helloMessage.getClientId());
assertEquals(1, helloMessage.getCapabilities().size());
assertEquals("eth", helloMessage.getCapabilities().get(0));
assertEquals(30303, helloMessage.getListenPort());
assertEquals(
"E02B18FBA6B887FB9258469C3AF8E445CC9AE2B5386CAC5F60C4170F822086224E3876555C745A7EC8AC181C7F9701776D94A779604EA12651DE5F4A748D29E1",
Hex.toHexString(helloMessage.getPeerId()).toUpperCase() );
assertEquals("cadfb93d2bb5fbe2943584d93ed90e374667c9e8b2502e974693ccc6b3d370bd4cde7738d0b626e3d2f3caecc59e1302d1711bf595711060d7b4921e18b97656",
Hex.toHexString(helloMessage.getPeerId()));
}
@Test /* HelloMessage 3 from new */
public void testFromNew() {
String helloAnnouncement = "Ethereum(J)/0.6.0/dev/Windows/Java";
byte p2pVersion = 0x00;
List<String> capabilities = new ArrayList<>(Arrays.asList("eth", "shh"));
short listenPort = (short) 30303;
byte[] peerIdBytes = Hex.decode("CAB0D93EEE1F44EF1286367101F1553450E3DDCE"
+ "EA45ABCAB0AC21E1EFB48A6610EBE88CE7317EB09229558311BA8B7250911D"
+ "7E49562C3988CA3143329DA3EA");
HelloMessage helloMessage = new HelloMessage(p2pVersion, helloAnnouncement,
capabilities, listenPort, peerIdBytes);
System.out.println(helloMessage);
// rlp encoded hello message
String expected = "F8738080A2457468657265756D284A292F302E362E302F6465762F5"
+ "7696E646F77732F4A617661C8836574688373686882765FB840CAB0D93EEE1F"
+ "44EF1286367101F1553450E3DDCEEA45ABCAB0AC21E1EFB48A6610EBE88CE73"
+ "17EB09229558311BA8B7250911D7E49562C3988CA3143329DA3EA";
assertEquals(expected, Hex.toHexString(helloMessage.getEncoded()).toUpperCase());
}
}

View File

@ -2,34 +2,55 @@ package org.ethereum.net;
import static org.junit.Assert.assertEquals;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import org.ethereum.net.client.PeerData;
import org.ethereum.net.client.Peer;
import org.ethereum.net.message.GetPeersMessage;
import org.ethereum.net.message.PeersMessage;
import org.ethereum.util.RLP;
import org.ethereum.util.RLPList;
import org.junit.Test;
import org.spongycastle.util.encoders.Hex;
public class PeersMessageTest {
/* GET_PEERS */
@Test /* GetPeersMessage */
public void testGetPeers() {
GetPeersMessage getPeersMessage = new GetPeersMessage();
System.out.println(getPeersMessage);
assertEquals(PeersMessage.class, getPeersMessage.getAnswerMessage());
}
/* PEERS */
@Test /* PeersMessage 1*/
public void test_5() {
@Test /* PeersMessage 1 from RLP */
public void testPeers_1() {
String peersMessageRaw = "F89911F84A84364845B482765FB840430BB21ECF73A54AEF511404948C016532406B371EDABD20A478C3ECD22052A0065A7399A6D19594E24B153930E63A3B12B3BA4F30A3CDA1977D60D4060FFF25F84A845163E11282765FB8405F1DBE5E50E92A6B67377E079D986155C0D82D964E65332F524810ED7831A52837F1C0FB042EA2A25548E3B444C337F54C7547B2D877734E2899F40BFA23ED51";
String peersMessageRaw = "F8 99 05 F8 4A 84 36 48 45 B4 82 76 "
+ "5F B8 40 43 0B B2 1E CF 73 A5 4A EF 51 14 04 94 8C "
+ "01 65 32 40 6B 37 1E DA BD 20 A4 78 C3 EC D2 20 52 "
+ "A0 06 5A 73 99 A6 D1 95 94 E2 4B 15 39 30 E6 3A 3B "
+ "12 B3 BA 4F 30 A3 CD A1 97 7D 60 D4 06 0F FF 25 F8 "
+ "4A 84 51 63 E1 12 82 76 5F B8 40 5F 1D BE 5E 50 E9 "
+ "2A 6B 67 37 7E 07 9D 98 61 55 C0 D8 2D 96 4E 65 33 "
+ "2F 52 48 10 ED 78 31 A5 28 37 F1 C0 FB 04 2E A2 A2 "
+ "55 48 E3 B4 44 C3 37 F5 4C 75 47 B2 D8 77 73 4E 28 "
+ "99 F4 0B FA 23 ED 51";
byte[] payload = Hex.decode(peersMessageRaw);
RLPList rlpList = RLP.decode2(payload);
PeersMessage peersMessage= new PeersMessage(rlpList);
PeersMessage peersMessage= new PeersMessage(payload);
System.out.println(peersMessage);
assertEquals(2, peersMessage.getPeers().size());
Iterator<PeerData> it = peersMessage.getPeers().iterator(); it.next();
PeerData peerData = it.next();
Iterator<Peer> it = peersMessage.getPeers().iterator(); it.next();
Peer peerData = it.next();
assertEquals("/81.99.225.18", peerData.getInetAddress().toString());
assertEquals(30303, peerData.getPort());
@ -37,24 +58,42 @@ public class PeersMessageTest {
Hex.toHexString(peerData.getPeerId()).toUpperCase());
}
@Test /* PeersMessage 2 from constructor */
public void testPeers_2() throws UnknownHostException {
Set<Peer> peers = new HashSet<>();
peers.add(new Peer(InetAddress.getByName("82.217.72.169").getAddress(), 30303, Hex.decode("585764a3c49a3838c69ad0855abfeb5672f71b072af62082b5679961781100814b8de88a8fbc1da7c73791f88159d73b5d2a13a5579535d603e045c3db5cbb75")));
peers.add(new Peer(InetAddress.getByName("192.168.1.193").getAddress(), 30303, new byte[0]));
PeersMessage peersMessage = new PeersMessage(peers);
System.out.println(peersMessage.toString());
String expected = "f85905f84b8452d948a982765fb840585764a3c49a3838c69ad0855abfeb5672f71b072af62082b5679961781100814b8de88a8fbc1da7c73791f88159d73b5d2a13a5579535d603e045c3db5cbb75c0ca84c0a801c182765f80c0";
assertEquals(expected, Hex.toHexString(peersMessage.getEncoded()));
}
@Test /* Peers msg parsing performance */
public void test_7() throws UnknownHostException {
public void testPeersPerformance() throws UnknownHostException {
long time1 = System.currentTimeMillis();
for (int i = 0; i < 20000; ++i) {
String peersPacketRaw = "F89911F84A84364845B482765FB840430BB21ECF73A54AEF511404948C016532406B371EDABD20A478C3ECD22052A0065A7399A6D19594E24B153930E63A3B12B3BA4F30A3CDA1977D60D4060FFF25F84A845163E11282765FB8405F1DBE5E50E92A6B67377E079D986155C0D82D964E65332F524810ED7831A52837F1C0FB042EA2A25548E3B444C337F54C7547B2D877734E2899F40BFA23ED51";
String peersPacketRaw = "F8 99 05 F8 4A 84 36 48 45 B4 82 76 "
+ "5F B8 40 43 0B B2 1E CF 73 A5 4A EF 51 14 04 94 "
+ "8C 01 65 32 40 6B 37 1E DA BD 20 A4 78 C3 EC D2 "
+ "20 52 A0 06 5A 73 99 A6 D1 95 94 E2 4B 15 39 30 "
+ "E6 3A 3B 12 B3 BA 4F 30 A3 CD A1 97 7D 60 D4 06 "
+ "0F FF 25 F8 4A 84 51 63 E1 12 82 76 5F B8 40 5F "
+ "1D BE 5E 50 E9 2A 6B 67 37 7E 07 9D 98 61 55 C0 "
+ "D8 2D 96 4E 65 33 2F 52 48 10 ED 78 31 A5 28 37 "
+ "F1 C0 FB 04 2E A2 A2 55 48 E3 B4 44 C3 37 F5 4C "
+ "75 47 B2 D8 77 73 4E 28 99 F4 0B FA 23 ED 51";
byte[] payload = Hex.decode(peersPacketRaw);
RLPList rlpList = RLP.decode2(payload);
PeersMessage peersMessage = new PeersMessage(rlpList);
peersMessage.parseRLP();
PeersMessage peersMessage = new PeersMessage(payload);
peersMessage.parse();
}
long time2 = System.currentTimeMillis();
System.out.println("20,000 PEERS packets parsing: " + (time2 - time1) + "(msec)");
}
}

View File

@ -2,7 +2,6 @@ package org.ethereum.net;
import static org.junit.Assert.assertEquals;
import org.ethereum.net.message.HelloMessage;
import org.ethereum.net.message.StatusMessage;
import org.junit.Test;
import org.spongycastle.util.encoders.Hex;
@ -11,46 +10,40 @@ public class StatusMessageTest {
/* STATUS_MESSAGE */
@Test /* StatusMessage 1 from PeerServer */
public void testPeer() {
@Test /* StatusMessage 1 from network */
public void test_1() {
String statusMessageRaw = "";
byte[] payload = Hex.decode(statusMessageRaw);
StatusMessage statusMessage = new StatusMessage(payload);
System.out.println(statusMessage);
assertEquals(0, statusMessage.getGenesisHash());
assertEquals(0, statusMessage.getNetworkId());
assertEquals(0, statusMessage.getProtocolVersion());
assertEquals(0, statusMessage.getTotalDifficulty());
assertEquals(0, statusMessage.getBestHash());
assertEquals(0, statusMessage.getNetworkId());
assertEquals("", Hex.toHexString(statusMessage.getTotalDifficulty()));
assertEquals("", Hex.toHexString(statusMessage.getBestHash()));
assertEquals("", Hex.toHexString(statusMessage.getGenesisHash()));
}
@Test /* HelloMessage 2 from Node */
public void testNode() {
String helloMessageRaw = "F8 80 80 80 B7 45 74 68 " +
"65 72 65 75 6D 28 2B 2B 29 2F 50 65 65 72 20 53 " +
"65 72 76 65 72 20 5A 65 72 6F 2F 76 30 2E 36 2E " +
"38 64 2F 52 65 6C 65 61 73 65 2F 4C 69 6E 75 78 " +
"2F 67 2B 2B C0 82 76 5F B8 40 20 17 B9 5D 55 86 " +
"AD D0 53 E7 C5 DC C8 11 2D B1 D5 57 ED 83 58 9C " +
"4E 0B D2 54 42 F3 9E 41 11 65 5A 48 72 57 AA 7E " +
"4E D3 09 E8 B4 D5 5B E5 FA 8D 8D 6E 97 B7 2C 67 " +
"D7 6A A0 3E B6 9A D9 81 ED 60";
@Test /* StatusMessage 1 from new */
public void test_2() {
byte protocolVersion = 0, networkId = 0;
byte[] totalDifficulty = Hex.decode("ff");
byte[] bestHash = Hex.decode("ff");
byte[] genesisHash = Hex.decode("ff");
byte[] payload = Hex.decode(helloMessageRaw);
HelloMessage helloMessage = new HelloMessage(payload);
helloMessage.parse();
System.out.println(helloMessage);
StatusMessage statusMessage = new StatusMessage(protocolVersion,
networkId, totalDifficulty, bestHash, genesisHash);
System.out.println(statusMessage);
assertEquals(0, helloMessage.getP2PVersion());
assertEquals("Ethereum(++)/Nick/v0.6.8d/Release/Linux/g++", helloMessage.getClientId());
assertEquals(3, helloMessage.getCapabilities().size());
assertEquals(30303, helloMessage.getListenPort());
assertEquals(
"2017B95D5586ADD053E7C5DCC8112DB1D557ED83589C4E0BD25442F39E4111655A487257AA7E4ED309E8B4D55BE5FA8D8D6E97B72C67D76AA03EB69AD981ED60",
Hex.toHexString(helloMessage.getPeerId()).toUpperCase() );
String expected = "ff";
assertEquals(expected, statusMessage.getEncoded());
assertEquals(0, statusMessage.getProtocolVersion());
assertEquals(0, statusMessage.getNetworkId());
assertEquals("", Hex.toHexString(statusMessage.getTotalDifficulty()));
assertEquals("", Hex.toHexString(statusMessage.getBestHash()));
assertEquals("", Hex.toHexString(statusMessage.getGenesisHash()));
}
}

View File

@ -12,8 +12,6 @@ import org.ethereum.crypto.ECKey;
import org.ethereum.crypto.HashUtil;
import org.ethereum.net.message.TransactionsMessage;
import org.ethereum.util.ByteUtil;
import org.ethereum.util.RLP;
import org.ethereum.util.RLPList;
import org.junit.Test;
import org.spongycastle.util.encoders.Hex;
@ -22,7 +20,7 @@ public class TransactionsMessageTest {
/* TRANSACTIONS */
@Test /* Transactions message 1 */
public void test_8() {
public void test_1() {
String txsPacketRaw = "f86e12f86b04648609184e72a00094cd2a3d9f938e13cd947ec05abc7fe734df8dd826"
+ "881bc16d674ec80000801ba05c89ebf2b77eeab88251e553f6f9d53badc1d800"
@ -30,9 +28,8 @@ public class TransactionsMessageTest {
+ "daa3653a8d9f424c6a3265f06c";
byte[] payload = Hex.decode(txsPacketRaw);
RLPList rlpList = RLP.decode2(payload);
TransactionsMessage transactionsMessage = new TransactionsMessage(rlpList);
TransactionsMessage transactionsMessage = new TransactionsMessage(payload);
System.out.println(transactionsMessage);
assertEquals(1, transactionsMessage.getTransactions().size());
@ -45,7 +42,7 @@ public class TransactionsMessageTest {
assertEquals("cd2a3d9f938e13cd947ec05abc7fe734df8dd826", Hex.toHexString(tx.getReceiveAddress()));
assertEquals("64", Hex.toHexString(tx.getGasPrice()));
assertEquals("09184e72a000", Hex.toHexString(tx.getGasLimit()));
assertEquals("null", ByteUtil.toHexString(tx.getData()));
assertEquals("", ByteUtil.toHexString(tx.getData()));
assertEquals("1b", Hex.toHexString(new byte[] { tx.getSignature().v }));
assertEquals("5c89ebf2b77eeab88251e553f6f9d53badc1d800bbac02d830801c2aa94a4c9f", Hex.toHexString(tx.getSignature().r.toByteArray()));
@ -53,7 +50,7 @@ public class TransactionsMessageTest {
}
@Test /* Transactions message 2 */
public void test_9() {
public void test_2() {
String txsPacketRaw = "f9025012f89d8080940000000000000000000000000000000000000000860918"
+ "4e72a000822710b3606956330c0d630000003359366000530a0d630000003359"
@ -76,15 +73,13 @@ public class TransactionsMessageTest {
+ "d7393152a7fbe41530e5bb8ac8f35433e5931b";
byte[] payload = Hex.decode(txsPacketRaw);
RLPList rlpList = RLP.decode2(payload);
TransactionsMessage transactionsMessage = new TransactionsMessage(rlpList);
TransactionsMessage transactionsMessage = new TransactionsMessage(payload);
System.out.println(transactionsMessage);
assertEquals(3, transactionsMessage.getTransactions().size());
Transaction tx =
transactionsMessage.getTransactions().get(0);
Transaction tx = transactionsMessage.getTransactions().get(0);
assertEquals("1b9d9456293cbcbc2f28a0fdc67028128ea571b033fb0e21d0ee00bcd6167e5d",
Hex.toHexString(tx.getHash()));
@ -148,7 +143,7 @@ public class TransactionsMessageTest {
}
@Test /* Transactions msg encode */
public void test15() throws Exception {
public void test_3() throws Exception {
String expected = "f87312f870808b00d3c21bcecceda10000009479b08ad8787060333663d19704909ee7b1903e588609184e72a000824255801ca00f410a70e42b2c9854a8421d32c87c370a2b9fff0a27f9f031bb4443681d73b5a018a7dc4c4f9dee9f3dc35cb96ca15859aa27e219a8e4a8547be6bd3206979858";
@ -166,11 +161,11 @@ public class TransactionsMessageTest {
tx.sign(privKey);
tx.getEncoded();
List<Transaction> txList = new ArrayList<Transaction>();
List<Transaction> txList = new ArrayList<>();
txList.add(tx);
TransactionsMessage transactionsMessage = new TransactionsMessage(txList);
assertEquals(expected, Hex.toHexString( transactionsMessage.getPayload()) );
assertEquals(expected, Hex.toHexString(transactionsMessage.getEncoded()));
}
}

View File

@ -642,7 +642,7 @@ public class TrieTest {
if(massiveUpdateFromDBEnabled) {
List<String> randomWords = Arrays.asList(randomDictionary.split(","));
HashMap<String, String> testerMap = new HashMap<>();
Map<String, String> testerMap = new HashMap<>();
TrieImpl trie = new TrieImpl(mockDb);
Random generator = new Random();

View File

@ -23,9 +23,33 @@ public class ByteUtilTest {
// fail("Not yet implemented");
// }
@Test
public void testToStringDoubleByteArray_1() {
String expected = "eth";
byte[][] input = new byte[][]{"eth".getBytes()};
String result = ByteUtil.toString(input);
assertEquals(expected, result);
}
@Test
public void testToStringDoubleByteArray_2() {
String expected = "eth shh";
byte[][] input = new byte[][]{"eth".getBytes(), "shh".getBytes()};
String result = ByteUtil.toString(input);
assertEquals(expected, result);
}
@Test
public void testToStringDoubleByteArray_3() {
String expected = "";
byte[][] input = new byte[0][];
String result = ByteUtil.toString(input);
assertEquals(expected, result);
}
@Test
public void testToHexString() {
assertEquals("null", ByteUtil.toHexString(null));
assertEquals("", ByteUtil.toHexString(null));
}
@Test

View File

@ -305,7 +305,7 @@ public class RLPTest {
String tx = "F86E12F86B80881BC16D674EC8000094CD2A3D9F938E13CD947EC05ABC7FE734DF8DD8268609184E72A00064801BA0C52C114D4F5A3BA904A9B3036E5E118FE0DBB987FE3955DA20F2CD8F6C21AB9CA06BA4C2874299A55AD947DBC98A25EE895AABF6B625C26C435E84BFD70EDF2F69";
byte[] payload = Hex.decode(tx);
Queue<Integer> index = new LinkedList<Integer>();
Queue<Integer> index = new LinkedList<>();
RLP.fullTraverse(payload, 0, 0, payload.length, 1, index);
// TODO: assert lenght overflow while parsing list in RLP

View File

@ -50,8 +50,7 @@ public class ValueTest {
String testRlp = "f7808080d387206f72726563748a626574656c676575736580d387207870726573738a70726564696361626c658080808080808080808080";
Value val =
Value.fromRlpEncoded(Hex.decode(testRlp));
Value val = Value.fromRlpEncoded(Hex.decode(testRlp));
assertEquals(testRlp, Hex.toHexString(val.encode()));
}

View File

@ -7,7 +7,6 @@ import org.ethereum.core.Wallet;
import org.ethereum.db.ContractDetails;
import org.ethereum.util.ByteUtil;
import org.ethereum.util.Utils;
import org.ethereum.vm.DataWord;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.spongycastle.util.BigIntegers;
@ -26,8 +25,6 @@ import java.math.BigInteger;
import java.net.URL;
import java.util.Collection;
import java.util.Map;
import java.util.regex.Pattern;
/**
* www.ethereumJ.com
* @author: Roman Mandeleil

View File

@ -10,7 +10,7 @@ import javax.swing.table.AbstractTableModel;
import org.ethereum.geo.IpGeoDB;
import org.ethereum.net.client.PeerData;
import org.ethereum.net.client.Peer;
import org.ethereum.net.message.HelloMessage;
import org.ethereum.util.Utils;
@ -23,7 +23,7 @@ import com.maxmind.geoip.Location;
*/
public class PeersTableModel extends AbstractTableModel {
private List<PeerInfo> peerInfoList = new ArrayList<PeerInfo>();
private List<PeerInfo> peerInfoList = new ArrayList<>();
Timer updater = new Timer();
public PeersTableModel() {
@ -111,11 +111,11 @@ public class PeersTableModel extends AbstractTableModel {
synchronized (peerInfoList) {
peerInfoList.clear();
final Set<PeerData> peers = UIEthereumManager.ethereum.getPeers();
final Set<Peer> peers = UIEthereumManager.ethereum.getPeers();
synchronized (peers){
for (PeerData peer : peers) {
for (Peer peer : peers) {
InetAddress addr = peer.getInetAddress();
Location cr = IpGeoDB.getLocationForIp(addr);
peerInfoList.add(new PeerInfo(cr, addr, peer.isOnline(), peer.getHandshake(), peer.getLastCheckTime()));

View File

@ -2,7 +2,6 @@ package org.ethereum.gui;
import org.ethereum.core.Block;
import org.ethereum.core.Transaction;
import org.ethereum.facade.Repository;
import org.ethereum.manager.WorldManager;
import org.ethereum.vm.*;
import org.spongycastle.util.encoders.Hex;

View File

@ -38,7 +38,6 @@ import org.ethereum.manager.WorldManager;
import org.ethereum.util.Utils;
import org.ethereum.vm.DataWord;
import org.ethereum.vm.Program;
import org.spongycastle.util.encoders.DecoderException;
import org.spongycastle.util.encoders.Hex;
import java.awt.Component;