diff --git a/ethereumj-core/src/main/java/org/ethereum/core/BlockchainImpl.java b/ethereumj-core/src/main/java/org/ethereum/core/BlockchainImpl.java index e8ddf596..2e2b5b37 100644 --- a/ethereumj-core/src/main/java/org/ethereum/core/BlockchainImpl.java +++ b/ethereumj-core/src/main/java/org/ethereum/core/BlockchainImpl.java @@ -42,7 +42,7 @@ import static org.ethereum.core.Denomination.SZABO; *
  • Let S_FINAL be S[n], but adding the block reward paid to the miner.
  • *
  • Check if S_FINAL is the same as the STATE_ROOT. If it is, the block is valid; otherwise, it is not valid.
  • * - * See Ethereum Whitepaper + * See Ethereum Whitepaper * * * www.ethereumJ.com @@ -104,7 +104,7 @@ public class BlockchainImpl implements Blockchain { block.getParentHash())) { return; } - // if there is some blocks already keep chain continuity + // if there are some blocks already keep chain continuity if (!blockCache.isEmpty()) { String hashLast = Hex.toHexString(getLastBlock().getHash()); String blockParentHash = Hex.toHexString(block.getParentHash()); diff --git a/ethereumj-core/src/main/java/org/ethereum/net/BlockQueue.java b/ethereumj-core/src/main/java/org/ethereum/net/BlockQueue.java index eeb5c633..07b88ca8 100644 --- a/ethereumj-core/src/main/java/org/ethereum/net/BlockQueue.java +++ b/ethereumj-core/src/main/java/org/ethereum/net/BlockQueue.java @@ -12,84 +12,85 @@ import java.util.concurrent.ConcurrentLinkedQueue; /** * www.ethereumJ.com * - * @author: Roman Mandeleil + * @author: Roman Mandeleil * Created on: 27/07/2014 11:28 */ public class BlockQueue { - private static Logger logger = LoggerFactory.getLogger("blockchain"); + private static Logger logger = LoggerFactory.getLogger("blockchain"); - private Queue blockQueue = new ConcurrentLinkedQueue<>(); - private Block lastBlock; + private Queue blockQueue = new ConcurrentLinkedQueue<>(); + private Block lastBlock; - private Timer timer = new Timer("BlockQueueTimer"); + private Timer timer = new Timer("BlockQueueTimer"); - public BlockQueue() { + public BlockQueue() { - timer.scheduleAtFixedRate (new TimerTask() { + timer.scheduleAtFixedRate(new TimerTask() { - public void run() { - nudgeQueue(); - } - }, 10, 10); - } + public void run() { + nudgeQueue(); + } + }, 10, 10); + } - private void nudgeQueue() { - if (blockQueue.isEmpty()) return; + private void nudgeQueue() { + if (blockQueue.isEmpty()) + return; + + Block block = blockQueue.poll(); + WorldManager.getInstance().getBlockchain().add(block); + } - Block block = blockQueue.poll(); + public void addBlocks(List blockList) { - WorldManager.getInstance().getBlockchain().add(block); - } + Block lastReceivedBlock = blockList.get(blockList.size() - 1); + if (lastReceivedBlock.getNumber() != getLast().getNumber() + 1) + return; - public void addBlocks(List blockList) { + for (int i = blockList.size() - 1; i >= 0; --i) { - Block lastReceivedBlock = blockList.get(blockList.size() - 1); - if (lastReceivedBlock.getNumber() != getLast().getNumber() + 1) return; + if (blockQueue.size() > SystemProperties.CONFIG.maxBlocksQueued()) + return; - for (int i = blockList.size() - 1; i >= 0; --i) { + this.lastBlock = blockList.get(i); + logger.trace("Last block now index: [ {} ]", lastBlock.getNumber()); + blockQueue.add(lastBlock); + } + logger.trace("Blocks waiting to be proceed in the queue: [ {} ]", + blockQueue.size()); + } - if (blockQueue.size() > - SystemProperties.CONFIG.maxBlocksQueued()) return; + public Block getLast() { + if (blockQueue.isEmpty()) + return WorldManager.getInstance().getBlockchain().getLastBlock(); + return lastBlock; + } - this.lastBlock = blockList.get(i); - logger.trace("Last block now index: [ {} ]", lastBlock.getNumber()); - blockQueue.add(lastBlock); - } + private class BlockByIndexComparator implements Comparator { - logger.trace("Blocks waiting to be proceed in the queue: [ {} ]", blockQueue.size()); - } + @Override + public int compare(Block o1, Block o2) { - public Block getLast() { + if (o1 == null || o2 == null) + throw new NullPointerException(); - if (blockQueue.isEmpty()) - return WorldManager.getInstance().getBlockchain().getLastBlock(); + if (o1.getNumber() > o2.getNumber()) + return 1; + if (o1.getNumber() < o2.getNumber()) + return -1; - return lastBlock; - } + return 0; + } + } - private class BlockByIndexComparator implements Comparator { - - @Override - public int compare(Block o1, Block o2) { - - if (o1 == null || o2 == null ) throw new NullPointerException(); - - if (o1.getNumber() > o2.getNumber()) return 1; - if (o1.getNumber() < o2.getNumber()) return -1; - - return 0; - } - } - - public int size() { - return blockQueue.size(); - } - - public void close(){ - timer.cancel(); - timer.purge(); - } + public int size() { + return blockQueue.size(); + } + public void close() { + timer.cancel(); + timer.purge(); + } } diff --git a/ethereumj-core/src/main/java/org/ethereum/net/Command.java b/ethereumj-core/src/main/java/org/ethereum/net/Command.java index ac9edfe7..f8d145dc 100644 --- a/ethereumj-core/src/main/java/org/ethereum/net/Command.java +++ b/ethereumj-core/src/main/java/org/ethereum/net/Command.java @@ -3,19 +3,89 @@ package org.ethereum.net; import java.util.HashMap; import java.util.Map; +/** + * A list of commands for the Ethereum network protocol. + *
    + * The codes for these commands are the first byte in every packet. + * + * @see + * https://github.com/ethereum/wiki/wiki/Wire-Protocol
    + * + * https://github.com/ethereum/cpp-ethereum/wiki/ÐΞVP2P-Networking
    + * + * https://github.com/ethereum/cpp-ethereum/wiki/PoC-6-Network-Protocol + */ public enum Command { + /* P2P */ + + /** [0x00, P2P_VERSION, CLIEND_ID, CAPS, LISTEN_PORT, CLIENT_ID]
    + * First packet sent over the connection, and sent once by both sides. + * No other messages may be sent until a Hello is received. */ HELLO(0x00), + + /** [0x01, REASON]
    Inform the peer that a disconnection is imminent; + * if received, a peer should disconnect immediately. When sending, + * well-behaved hosts give their peers a fighting chance (read: wait 2 seconds) + * to disconnect to before disconnecting themselves. */ DISCONNECT(0x01), + + /** [0x02]
    Requests an immediate reply of Pong from the peer. */ PING(0x02), + + /** [0x03]
    Reply to peer's Ping packet. */ PONG(0x03), - GET_PEERS(0x10), - PEERS(0x11), + + /** [0x04]
    Request the peer to enumerate some known peers + * for us to connect to. This should include the peer itself. */ + GET_PEERS(0x04), + + /** [0x05, [IP1, Port1, Id1], [IP2, Port2, Id2], ... ]
    + * Specifies a number of known peers. IP is a 4-byte array 'ABCD' + * that should be interpreted as the IP address A.B.C.D. + * Port is a 2-byte array that should be interpreted as a + * 16-bit big-endian integer. Id is the 512-bit hash that acts + * as the unique identifier of the node. */ + PEERS(0x05), + + /** [0x10, [PROTOCOL_VERSION, NETWORK_ID, TD, BEST_HASH, GENESIS_HASH]
    + * Inform a peer of it's current ethereum state. This message should be + * send after the initial handshake and prior to any ethereum related messages. */ + STATUS(0x10), + + /* Ethereum */ + + /** [0x12, [nonce, receiving_address, value, ... ], ... ]
    + * Specify (a) transaction(s) that the peer should make sure is included + * on its transaction queue. The items in the list (following the first item 0x12) + * are transactions in the format described in the main Ethereum specification. */ TRANSACTIONS(0x12), + + /** [0x13, [block_header, transaction_list, uncle_list], ... ]
    + * Specify (a) block(s) that the peer should know about. + * The items in the list (following the first item, 0x13) + * are blocks in the format described in the main Ethereum specification. */ BLOCKS(0x13), - GET_CHAIN(0x14), - NOT_IN_CHAIN(0x15), GET_TRANSACTIONS(0x16), + + /** [0x17, [ hash : B_32, maxBlocks: P ]:
    + * Requests a BlockHashes message of at most maxBlocks entries, + * of block hashes from the blockchain, starting at the parent of block hash. + * Does not require the peer to give maxBlocks hashes - + * they could give somewhat fewer. */ + GET_BLOCK_HASHES(0x17), + + /** [0x18, [ hash_0: B_32, hash_1: B_32, .... ]:
    Gives a series of hashes + * of blocks (each the child of the next). This implies that the blocks + * are ordered from youngest to oldest. */ + BLOCK_HASHES(0x18), + + /** [0x19, [ hash_0: B_32, hash_1: B_32, .... ]:
    Requests a Blocks message + * detailing a number of blocks to be sent, each referred to by a hash.
    + * Note: Don't expect that the peer necessarily give you all these blocks + * in a single message - you might have to re-request them. */ + GET_BLOCKS(0x19), + UNKNOWN(0xFF); private int cmd; diff --git a/ethereumj-core/src/main/java/org/ethereum/net/MessageQueue.java b/ethereumj-core/src/main/java/org/ethereum/net/MessageQueue.java index 501aa970..461e21e8 100644 --- a/ethereumj-core/src/main/java/org/ethereum/net/MessageQueue.java +++ b/ethereumj-core/src/main/java/org/ethereum/net/MessageQueue.java @@ -12,63 +12,60 @@ import java.util.*; import java.util.concurrent.ConcurrentLinkedQueue; /** - * www.ethereumJ.com + * This class contains the logic for sending messages in a queue * - * @author: Roman Mandeleil - * Created on: 09/07/2014 10:29 + * Messages open by send and answered by receive of appropriate message + * GET_BLOCK_HASHES by BLOCK_HASHES + * GET_BLOCKS by BLOCKS + * PING by PONG + * GET_PEERS by PEERS + * GET_TRANSACTIONS by TRANSACTIONS + * + * The following messages will not be answered: + * PONG, PEERS, BLOCKS, TRANSACTIONS + * + * @author Roman Mandeleil */ - public class MessageQueue { - // 1) queue for messages - // 2) process for sending messages - - // 3) messages open by send and answered by receive of appropriate message - // GET_CHAIN by BLOCKS - // PING by PONG - // GET_PEERS by PEERS - // GET_TRANSACTIONS by TRANSACTIONS - // messages will not be answered: TRANSACTIONS, PONG, PEERS, TRANSACTIONS - private Logger logger = LoggerFactory.getLogger("wire"); - Queue messageQueue = new ConcurrentLinkedQueue<>(); - ChannelHandlerContext ctx = null; - Timer timer = new Timer(); + private Queue messageQueue = new ConcurrentLinkedQueue<>(); + private ChannelHandlerContext ctx = null; + private Timer timer = new Timer(); - public MessageQueue(ChannelHandlerContext ctx) { - this.ctx = ctx; + public MessageQueue(ChannelHandlerContext ctx) { + this.ctx = ctx; - timer.scheduleAtFixedRate (new TimerTask() { + timer.scheduleAtFixedRate(new TimerTask() { + public void run() { + nudgeQueue(); + } + }, 10, 10); + } - public void run() { - nudgeQueue(); - } - }, 10, 10); - } + public void sendMessage(Message msg) { - public void sendMessage(Message msg){ - - if (msg instanceof GetChainMessage && containsGetChain()) + if (msg instanceof GetBlockHashesMessage && containsGetBlockHashes()) return; messageQueue.add(new MessageRoundtrip(msg)); } - public void receivedMessage(Message msg){ + public void receivedMessage(Message msg) { if (logger.isDebugEnabled()) logger.debug("Recv: [ {} ] - [ {} ]", msg.getMessageName(), Hex.toHexString(msg.getPayload())); - if (null != messageQueue.peek()) { MessageRoundtrip messageRoundtrip = messageQueue.peek(); Message waitingMessage = messageRoundtrip.getMsg(); - - if (waitingMessage.getAnswerMessage() == null) return; + + if (waitingMessage.getAnswerMessage() == null) + return; if (msg.getClass() == waitingMessage.getAnswerMessage()){ messageRoundtrip.answer(); @@ -77,7 +74,7 @@ public class MessageQueue { } } - private void nudgeQueue(){ + private void nudgeQueue() { // The message was answered, remove from the queue if (null != messageQueue.peek()) { @@ -89,18 +86,17 @@ public class MessageQueue { } // Now send the next message - if (null != messageQueue.peek()){ + if (null != messageQueue.peek()) { MessageRoundtrip messageRoundtrip = messageQueue.peek(); - if (messageRoundtrip.getRetryTimes() == 0 ) {// todo: retry logic || messageRoundtrip.hasToRetry()){ + if (messageRoundtrip.getRetryTimes() == 0 ) { + // todo: retry logic || messageRoundtrip.hasToRetry()){ Message msg = messageRoundtrip.getMsg(); sendToWire(msg); - if (msg.getAnswerMessage() == null){ - + if (msg.getAnswerMessage() == null) messageQueue.remove(); - } else { messageRoundtrip.incRetryTimes(); messageRoundtrip.saveTime(); @@ -109,7 +105,7 @@ public class MessageQueue { } } - private void sendToWire(Message msg){ + private void sendToWire(Message msg) { if (logger.isDebugEnabled()) logger.debug("Send: [ {} ] - [ {} ]", @@ -117,19 +113,19 @@ public class MessageQueue { Hex.toHexString(msg.getPayload())); ByteBuf buffer = ctx.alloc().buffer(msg.getPayload().length + 8); - buffer.writeBytes(StaticMessages.MAGIC_PACKET); + buffer.writeBytes(StaticMessages.SYNC_TOKEN); buffer.writeBytes(ByteUtil.calcPacketLength(msg.getPayload())); buffer.writeBytes(msg.getPayload()); ctx.writeAndFlush(buffer); } - private boolean containsGetChain(){ + private boolean containsGetBlockHashes() { Iterator iterator = messageQueue.iterator(); while(iterator.hasNext()){ MessageRoundtrip msgRoundTrip = iterator.next(); - if (msgRoundTrip.getMsg() instanceof GetChainMessage) + if (msgRoundTrip.getMsg() instanceof GetBlockHashesMessage) return true; } return false; diff --git a/ethereumj-core/src/main/java/org/ethereum/net/MessageRoundtrip.java b/ethereumj-core/src/main/java/org/ethereum/net/MessageRoundtrip.java index e29c189d..103a19a7 100644 --- a/ethereumj-core/src/main/java/org/ethereum/net/MessageRoundtrip.java +++ b/ethereumj-core/src/main/java/org/ethereum/net/MessageRoundtrip.java @@ -3,15 +3,15 @@ package org.ethereum.net; import org.ethereum.net.message.Message; /** - * www.ethereumJ.com - * - * @author: Roman Mandeleil - * Created on: 09/07/2014 13:54 + * Utility wraps around a message to keep track of the number of times it has been offered + * This class also contains the last time a message was offered and is updated + * when an answer has been received to it can be removed from the queue. + * + * @author Roman Mandeleil */ - public class MessageRoundtrip { - Message msg = null; + private Message msg = null; long lastTimestamp = 0; long retryTimes = 0; boolean answered = false; @@ -36,9 +36,12 @@ public class MessageRoundtrip { public void incRetryTimes(){ ++retryTimes; } - public void saveTime(){lastTimestamp = System.currentTimeMillis();} + + public void saveTime() { + lastTimestamp = System.currentTimeMillis(); + } - public boolean hasToRetry(){ + public boolean hasToRetry() { return 20000 < System.currentTimeMillis() - lastTimestamp; } diff --git a/ethereumj-core/src/main/java/org/ethereum/net/client/EthereumProtocolHandler.java b/ethereumj-core/src/main/java/org/ethereum/net/client/EthereumProtocolHandler.java index b7e71769..e97ab7b8 100644 --- a/ethereumj-core/src/main/java/org/ethereum/net/client/EthereumProtocolHandler.java +++ b/ethereumj-core/src/main/java/org/ethereum/net/client/EthereumProtocolHandler.java @@ -25,10 +25,6 @@ import java.util.Timer; import java.util.TimerTask; import static org.ethereum.net.Command.*; -import static org.ethereum.net.Command.GET_PEERS; -import static org.ethereum.net.Command.GET_TRANSACTIONS; -import static org.ethereum.net.Command.PING; -import static org.ethereum.net.Command.PONG; import static org.ethereum.net.message.StaticMessages.*; @@ -41,16 +37,13 @@ public class EthereumProtocolHandler extends ChannelInboundHandlerAdapter { private Logger logger = LoggerFactory.getLogger("wire"); - private Timer chainAskTimer = new Timer("ChainAskTimer"); - private int secToAskForChain = 1; - + private Timer blocksAskTimer = new Timer("ChainAskTimer"); private final Timer timer = new Timer("MiscMessageTimer"); - + + private int secToAskForBlocks = 1; private boolean tearDown = false; - private PeerListener peerListener; - - MessageQueue msgQueue = null; + private MessageQueue msgQueue = null; public EthereumProtocolHandler() { } @@ -91,12 +84,12 @@ public class EthereumProtocolHandler extends ChannelInboundHandlerAdapter { } }, 2000, 10000); - chainAskTimer.scheduleAtFixedRate(new TimerTask() { + blocksAskTimer.scheduleAtFixedRate(new TimerTask() { public void run() { - sendGetChain(); + sendGetBlocks(); } - }, 1000, secToAskForChain * 1000); + }, 1000, secToAskForBlocks * 1000); } @@ -108,11 +101,15 @@ public class EthereumProtocolHandler extends ChannelInboundHandlerAdapter { EthereumListener listener = WorldManager.getInstance().getListener(); - byte command = RLP.getCommandCode(payload); - - // got HELLO - if (Command.fromInt(command) == HELLO) { - logger.info("[Recv: HELLO]" ); + byte commandCode = RLP.getCommandCode(payload); + Command receivedCommand = Command.fromInt(commandCode); + + logger.info("[Recv: {}]", receivedCommand.name()); + if (peerListener != null) peerListener.console("[Recv: " + receivedCommand.name() + "]"); + + switch(receivedCommand) { + + case HELLO: RLPList rlpList = RLP.decode2(payload); HelloMessage helloMessage = new HelloMessage(rlpList); @@ -123,13 +120,8 @@ public class EthereumProtocolHandler extends ChannelInboundHandlerAdapter { listener.trace(String.format("Got handshake: [ %s ]", helloMessage.toString())); listener.onRecvMessage(helloMessage); } - - } - // got DISCONNECT - if (Command.fromInt(command) == DISCONNECT) { - - if (peerListener != null) peerListener.console("[Recv: DISCONNECT]"); - + break; + case DISCONNECT: DisconnectMessage disconnectMessage = new DisconnectMessage(payload); msgQueue.receivedMessage(disconnectMessage); @@ -138,45 +130,29 @@ public class EthereumProtocolHandler extends ChannelInboundHandlerAdapter { if (listener != null) listener.onRecvMessage(disconnectMessage); - - - } - - // got PING send pong - if (Command.fromInt(command) == PING) { - if (peerListener != null) peerListener.console("[Recv: PING]"); - msgQueue.receivedMessage(PING_MESSAGE); + break; + case PING: + msgQueue.receivedMessage(PING_MESSAGE); sendPong(); if (listener != null) listener.onRecvMessage(PING_MESSAGE); - } - - // got PONG mark it - if (Command.fromInt(command) == PONG) { - if (peerListener != null) peerListener.console("[Recv: PONG]"); + break; + case PONG: msgQueue.receivedMessage(PONG_MESSAGE); if (listener != null) listener.onRecvMessage(PONG_MESSAGE); - } - - // got GETPEERS send peers - if (Command.fromInt(command) == GET_PEERS) { - - if (peerListener != null) peerListener.console("[Recv: GETPEERS]"); - msgQueue.receivedMessage(GET_PEERS_MESSAGE); + break; + case GET_PEERS: + msgQueue.receivedMessage(GET_PEERS_MESSAGE); // TODO: send peer list if (listener != null) listener.onRecvMessage(GET_PEERS_MESSAGE); - } - - // got PEERS - if (Command.fromInt(command) == PEERS) { - if (peerListener != null) peerListener.console("[Recv: PEERS]"); - + break; + case PEERS: PeersMessage peersMessage = new PeersMessage(payload); msgQueue.receivedMessage(peersMessage); @@ -187,13 +163,9 @@ public class EthereumProtocolHandler extends ChannelInboundHandlerAdapter { if (listener != null) listener.onRecvMessage(peersMessage); - } - - // got TRANSACTIONS - if (Command.fromInt(command) == TRANSACTIONS) { - - if (peerListener != null) peerListener.console("Recv: TRANSACTIONS]"); - TransactionsMessage transactionsMessage = new TransactionsMessage(payload); + break; + case TRANSACTIONS: + TransactionsMessage transactionsMessage = new TransactionsMessage(payload); msgQueue.receivedMessage(transactionsMessage); List txList = transactionsMessage.getTransactions(); @@ -207,51 +179,44 @@ public class EthereumProtocolHandler extends ChannelInboundHandlerAdapter { if (listener != null) listener.onRecvMessage(transactionsMessage); - } - - // got BLOCKS - if (Command.fromInt(command) == BLOCKS) { - if (peerListener != null) peerListener.console("[Recv: BLOCKS]"); - + break; + case BLOCKS: BlocksMessage blocksMessage = new BlocksMessage(payload); List blockList = blocksMessage.getBlockDataList(); msgQueue.receivedMessage(blocksMessage); + // If we get one block from a peer we ask less greedy + if (blockList.size() <= 1 && secToAskForBlocks != 10) { - // If we get one block from a peer - // we ask less greedy - if (blockList.size() <= 1 && secToAskForChain != 10) { + logger.info("Now we ask for blocks each 10 seconds"); + secToAskForBlocks = 10; - logger.info("Now we ask for a chain each 10 seconds"); - secToAskForChain = 10; - - chainAskTimer.cancel(); - chainAskTimer.purge(); - chainAskTimer = new Timer(); - chainAskTimer.scheduleAtFixedRate(new TimerTask() { + blocksAskTimer.cancel(); + blocksAskTimer.purge(); + blocksAskTimer = new Timer(); + blocksAskTimer.scheduleAtFixedRate(new TimerTask() { public void run() { - sendGetChain(); + sendGetBlocks(); } - }, 3000, secToAskForChain * 1000); + }, 3000, secToAskForBlocks * 1000); } - // If we get more blocks from a peer - // we ask more greedy - if (blockList.size() > 2 && secToAskForChain != 1) { + // 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"); - secToAskForChain = 1; + secToAskForBlocks = 1; - chainAskTimer.cancel(); - chainAskTimer.purge(); - chainAskTimer = new Timer(); - chainAskTimer.scheduleAtFixedRate(new TimerTask() { + blocksAskTimer.cancel(); + blocksAskTimer.purge(); + blocksAskTimer = new Timer(); + blocksAskTimer.scheduleAtFixedRate(new TimerTask() { public void run() { - sendGetChain(); + sendGetBlocks(); } - }, 3000, secToAskForChain * 1000); + }, 3000, secToAskForBlocks * 1000); } if (blockList.isEmpty()) return; @@ -260,57 +225,32 @@ public class EthereumProtocolHandler extends ChannelInboundHandlerAdapter { if (listener != null) listener.onRecvMessage(blocksMessage); - } + break; + case GET_TRANSACTIONS: - // got GETCHAIN - if (Command.fromInt(command) == GET_CHAIN) { - logger.info("[Recv: GET_CHAIN]"); - if (peerListener != null) peerListener.console("[Recv: GET_CHAIN]"); - - RLPList rlpList = RLP.decode2(payload); - GetChainMessage getChainMessage = new GetChainMessage(rlpList); - - // todo: send blocks - - logger.info(getChainMessage.toString()); - if (peerListener != null) peerListener.console(getChainMessage.toString()); - - if (listener != null) - listener.onRecvMessage(getChainMessage); - } - - // got NOTINCHAIN - if (Command.fromInt(command) == NOT_IN_CHAIN) { - logger.info("[Recv: NOT_IN_CHAIN]"); - if (peerListener != null) peerListener.console("[Recv: NOT_IN_CHAIN]"); - - RLPList rlpList = RLP.decode2(payload); - NotInChainMessage notInChainMessage = new NotInChainMessage(rlpList); - - logger.info(notInChainMessage.toString()); - if (peerListener != null) peerListener.console(notInChainMessage.toString()); - - if (listener != null) - listener.onRecvMessage(notInChainMessage); - } - - // got GETTRANSACTIONS - if (Command.fromInt(command) == GET_TRANSACTIONS) { - logger.info("[Recv: GET_TRANSACTIONS]"); - if (peerListener != null) peerListener.console("[Recv: GET_TRANSACTIONS]"); - - // TODO: return it in the future -// Collection pendingTxList = -// MainData.instance.getBlockchain().getPendingTransactionList(); - -// TransactionsMessage txMsg = -// new TransactionsMessage(new ArrayList(pendingTxList)); + // TODO Implement GET_TRANSACTIONS command + +// List pendingTxList = +// WorldManager.getInstance().getBlockchain().getPendingTransactionList(); +// TransactionsMessage txMsg = new TransactionsMessage(pendingTxList); // sendMsg(txMsg, ctx); if (listener != null) listener.onRecvMessage(GET_TRANSACTIONS_MESSAGE); - + break; + case GET_BLOCK_HASHES: + // TODO Implement GET_BLOCK_HASHES command + break; + case BLOCK_HASHES: + // TODO Implement BLOCK_HASHES command + break; + case GET_BLOCKS: + // TODO Implement GET_BLOCKS command + break; + default: + // do nothing and ignore this command + break; } } @@ -354,7 +294,7 @@ public class EthereumProtocolHandler extends ChannelInboundHandlerAdapter { sendMsg(GET_TRANSACTIONS_MESSAGE); } - private void sendGetChain() { + private void sendGetBlocks() { if (WorldManager.getInstance().getBlockchain().getBlockQueue().size() > SystemProperties.CONFIG.maxBlocksQueued()) return; @@ -363,14 +303,14 @@ public class EthereumProtocolHandler extends ChannelInboundHandlerAdapter { if (lastBlock == null) return; byte[] hash = lastBlock.getHash(); - GetChainMessage chainMessage = - new GetChainMessage( SystemProperties.CONFIG.maxBlocksAsk(), hash); - sendMsg(chainMessage); + GetBlocksMessage getBlocksMessage = new GetBlocksMessage( + SystemProperties.CONFIG.maxBlocksAsk(), hash); + sendMsg(getBlocksMessage); } public void killTimers(){ - chainAskTimer.cancel(); - chainAskTimer.purge(); + blocksAskTimer.cancel(); + blocksAskTimer.purge(); timer.cancel(); timer.purge(); diff --git a/ethereumj-core/src/main/java/org/ethereum/net/message/BlockHashesMessage.java b/ethereumj-core/src/main/java/org/ethereum/net/message/BlockHashesMessage.java new file mode 100644 index 00000000..e33428b2 --- /dev/null +++ b/ethereumj-core/src/main/java/org/ethereum/net/message/BlockHashesMessage.java @@ -0,0 +1,29 @@ +package org.ethereum.net.message; + +public class BlockHashesMessage extends Message { + + @Override + public void parseRLP() { + // TODO Auto-generated method stub + + } + + @Override + public byte[] getPayload() { + // TODO Auto-generated method stub + return null; + } + + @Override + public String getMessageName() { + // TODO Auto-generated method stub + return null; + } + + @Override + public Class getAnswerMessage() { + // TODO Auto-generated method stub + return null; + } + +} diff --git a/ethereumj-core/src/main/java/org/ethereum/net/message/DisconnectMessage.java b/ethereumj-core/src/main/java/org/ethereum/net/message/DisconnectMessage.java index 4ed6a178..d941d709 100644 --- a/ethereumj-core/src/main/java/org/ethereum/net/message/DisconnectMessage.java +++ b/ethereumj-core/src/main/java/org/ethereum/net/message/DisconnectMessage.java @@ -6,7 +6,7 @@ import org.ethereum.util.RLPItem; import org.ethereum.util.RLPList; import static org.ethereum.net.Command.DISCONNECT; -import static org.ethereum.net.message.ReasonCode.DISCONNECT_REQUESTED; +import static org.ethereum.net.message.ReasonCode.REQUESTED; /** * www.ethereumJ.com @@ -22,7 +22,6 @@ public class DisconnectMessage extends Message { this.payload = payload; } - public DisconnectMessage(RLPList rawData) { super(rawData); } @@ -38,7 +37,7 @@ public class DisconnectMessage extends Message { byte[] reasonB = ((RLPItem)paramsList.get(1)).getRLPData(); if (reasonB == null) { - this.reason = DISCONNECT_REQUESTED; + this.reason = REQUESTED; } else { this.reason = ReasonCode.fromInt(reasonB[0]); } diff --git a/ethereumj-core/src/main/java/org/ethereum/net/message/GetBlockHashesMessage.java b/ethereumj-core/src/main/java/org/ethereum/net/message/GetBlockHashesMessage.java new file mode 100644 index 00000000..f094da94 --- /dev/null +++ b/ethereumj-core/src/main/java/org/ethereum/net/message/GetBlockHashesMessage.java @@ -0,0 +1,24 @@ +package org.ethereum.net.message; + +public class GetBlockHashesMessage extends Message { + + @Override + public void parseRLP() { + } + + @Override + public byte[] getPayload() { + return null; + } + + @Override + public String getMessageName() { + return "GetBlockHashes"; + } + + @Override + public Class getAnswerMessage() { + return BlockHashesMessage.class; + } + +} diff --git a/ethereumj-core/src/main/java/org/ethereum/net/message/GetChainMessage.java b/ethereumj-core/src/main/java/org/ethereum/net/message/GetBlocksMessage.java similarity index 53% rename from ethereumj-core/src/main/java/org/ethereum/net/message/GetChainMessage.java rename to ethereumj-core/src/main/java/org/ethereum/net/message/GetBlocksMessage.java index 3af03fde..ea580d98 100644 --- a/ethereumj-core/src/main/java/org/ethereum/net/message/GetChainMessage.java +++ b/ethereumj-core/src/main/java/org/ethereum/net/message/GetBlocksMessage.java @@ -1,106 +1,87 @@ -package org.ethereum.net.message; - -import java.math.BigInteger; -import java.util.ArrayList; -import java.util.List; - -import static org.ethereum.net.Command.GET_CHAIN; - -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; - -/** - * www.ethereumJ.com - * @author: Roman Mandeleil - * Created on: 06/04/14 14:56 - */ -public class GetChainMessage extends Message { - - private List blockHashList = new ArrayList(); - private BigInteger blockNum; - - public GetChainMessage(RLPList rawData) { - super(rawData); - } - - // TODO: it get's byte for now change it to int - public GetChainMessage(byte number , byte[]... blockHashList) { - - byte[][] encodedElements = new byte[blockHashList.length + 2][]; - - encodedElements[0] = new byte[]{0x14}; - int i = 1; - for (byte[] hash : blockHashList) { - this.blockHashList.add(hash); - byte[] element = RLP.encodeElement(hash); - encodedElements[i] = element; - ++i; - } - encodedElements[i] = RLP.encodeByte(number); - - this.payload = RLP.encodeList(encodedElements); - this.parsed = true; - } - - @Override - public void parseRLP() { - - RLPList paramsList = (RLPList) rawData.get(0); - - if (Command.fromInt(((RLPItem)(paramsList).get(0)).getRLPData()[0]) != GET_CHAIN) { - throw new Error("GetChain: parsing for mal data"); - } - - int size = paramsList.size(); - for (int i = 1; i < size - 1; ++i) { - blockHashList.add(((RLPItem) paramsList.get(i)).getRLPData()); - } - - // the last element is the num of requested blocks - byte[] blockNumB = ((RLPItem)paramsList.get(size - 1)).getRLPData(); - this.blockNum = new BigInteger(blockNumB); - - this.parsed = true; - // TODO: what to do when mal data ? - } - - @Override - public byte[] getPayload() { - return payload; - } - - public List getBlockHashList() { - if (!parsed) parseRLP(); - return blockHashList; - } - - public BigInteger getBlockNum() { - if (!parsed) parseRLP(); - return blockNum; - } - - @Override - public String getMessageName() { - return "GetChain"; - } - - @Override - public Class getAnswerMessage() { - return BlocksMessage.class; - } - - public String toString() { - - if (!parsed) parseRLP(); - - StringBuffer sb = new StringBuffer(); - for (byte[] blockHash : blockHashList) { - sb.append("").append(Hex.toHexString(blockHash)).append(", "); - } - sb.append(" blockNum=").append(blockNum); - return "GetChain Message [" + sb.toString() + " ]"; - } -} +package org.ethereum.net.message; + +import static org.ethereum.net.Command.GET_BLOCKS; + +import java.math.BigInteger; +import java.util.ArrayList; +import java.util.List; + +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; + +public class GetBlocksMessage extends Message { + + private List blockHashList = new ArrayList(); + private BigInteger blockNum; + + public GetBlocksMessage(RLPList rawData) { + super(rawData); + } + + // 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}; + int i = 1; + for (byte[] hash : blockHashList) { + this.blockHashList.add(hash); + byte[] element = RLP.encodeElement(hash); + encodedElements[i] = element; + ++i; + } + encodedElements[i] = RLP.encodeByte(number); + + this.payload = RLP.encodeList(encodedElements); + this.parsed = true; + } + + @Override + public void parseRLP() { + RLPList paramsList = (RLPList) rawData.get(0); + + if (Command.fromInt(((RLPItem) (paramsList).get(0)).getRLPData()[0]) != GET_BLOCKS) + throw new Error("GetBlocks: parsing for mal data"); + + int size = paramsList.size(); + for (int i = 1; i < size - 1; ++i) { + blockHashList.add(((RLPItem) paramsList.get(i)).getRLPData()); + } + + // the last element is the num of requested blocks + byte[] blockNumB = ((RLPItem) paramsList.get(size - 1)).getRLPData(); + this.blockNum = new BigInteger(blockNumB); + + this.parsed = true; + // TODO: what to do when mal data ? + } + + @Override + public byte[] getPayload() { + return payload; + } + + @Override + public String getMessageName() { + return "GetBlocks"; + } + + @Override + public Class getAnswerMessage() { + return BlocksMessage.class; + } + + public String toString() { + if (!parsed) parseRLP(); + + StringBuffer sb = new StringBuffer(); + for (byte[] blockHash : blockHashList) + sb.append("").append(Hex.toHexString(blockHash)).append(", "); + sb.append(" blockNum=").append(blockNum); + return "GetBlocks Message [" + sb.toString() + " ]"; + } +} diff --git a/ethereumj-core/src/main/java/org/ethereum/net/message/HelloMessage.java b/ethereumj-core/src/main/java/org/ethereum/net/message/HelloMessage.java index dd680a7e..59f81970 100644 --- a/ethereumj-core/src/main/java/org/ethereum/net/message/HelloMessage.java +++ b/ethereumj-core/src/main/java/org/ethereum/net/message/HelloMessage.java @@ -3,18 +3,20 @@ 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.util.RLP; import org.ethereum.util.RLPItem; import org.ethereum.util.RLPList; import java.math.BigInteger; -import java.nio.ByteBuffer; /** - * www.ethereumJ.com - * @author: Roman Mandeleil - * Created on: 06/04/14 14:56 + * Wrapper around an Ethereum HelloMessage on the network + * + * @see {@link org.ethereum.net.Command#HELLO} + * + * @author Roman Mandeleil */ public class HelloMessage extends Message { @@ -24,18 +26,30 @@ public class HelloMessage extends Message { private byte capabilities; private short peerPort; private byte[] peerId; + + /** Total difficulty of the best chain as found in block header. */ + private byte[] totalDifficulty; + /** The hash of the best (i.e. highest TD) known block. */ + private byte[] bestHash; + /** The hash of the Genesis block */ + private byte[] genesisHash; public HelloMessage(RLPList rawData) { super(rawData); } - public HelloMessage(byte protocolVersion, byte networkId, String clientId, byte capabilities, short peerPort, byte[] peerId) { + public HelloMessage(byte protocolVersion, byte networkId, String clientId, + byte capabilities, short peerPort, byte[] peerId, byte[] totalDifficulty, + byte[] bestHash, byte[] genesisHash) { this.protocolVersion = protocolVersion; this.networkId = networkId; this.clientId = clientId; this.capabilities = capabilities; this.peerPort = peerPort; this.peerId = peerId; + this.totalDifficulty = totalDifficulty; + this.bestHash = bestHash; + this.genesisHash = genesisHash; this.parsed = true; } @@ -49,35 +63,48 @@ public class HelloMessage extends Message { if (((RLPItem)paramsList.get(0)).getRLPData() != null) { throw new Error("HelloMessage: parsing for mal data"); } + + this.protocolVersion = ((RLPItem) paramsList.get(1)).getRLPData()[0]; + + byte[] networkIdBytes = ((RLPItem) paramsList.get(2)).getRLPData(); + this.networkId = networkIdBytes == null ? 0 : networkIdBytes[0]; + + byte[] clientIdBytes = ((RLPItem) paramsList.get(3)).getRLPData(); + this.clientId = new String(clientIdBytes != null ? clientIdBytes : EMPTY_BYTE_ARRAY); + + this.capabilities = ((RLPItem) paramsList.get(4)).getRLPData()[0]; - this.protocolVersion = ((RLPItem) paramsList.get(1)).getRLPData()[0]; - - byte[] networkIdBytes = ((RLPItem) paramsList.get(2)).getRLPData(); - this.networkId = networkIdBytes == null ? 0 : networkIdBytes[0] ; - - byte[] idData = ((RLPItem) paramsList.get(3)).getRLPData(); - this.clientId = new String(idData != null ? idData : new byte[0]); - this.capabilities = ((RLPItem) paramsList.get(4)).getRLPData()[0]; - - ByteBuffer bb = ByteBuffer.wrap(((RLPItem) paramsList.get(5)).getRLPData()); - this.peerPort = new BigInteger(bb.array()).shortValue(); - this.peerId = ((RLPItem) paramsList.get(6)).getRLPData(); + byte[] peerPortBytes = ((RLPItem) paramsList.get(5)).getRLPData(); + this.peerPort = new BigInteger(peerPortBytes).shortValue(); + + this.peerId = ((RLPItem) paramsList.get(6)).getRLPData(); + + this.totalDifficulty = ((RLPItem) paramsList.get(7)).getRLPData(); + + this.bestHash = ((RLPItem) paramsList.get(8)).getRLPData(); + + this.genesisHash = ((RLPItem) paramsList.get(9)).getRLPData(); + this.parsed = true; // TODO: what to do when mal data ? } public byte[] getPayload() { - byte[] command = RLP.encodeByte(HELLO.asByte()); - byte[] protocolVersion = RLP.encodeByte(this.protocolVersion); - byte[] networkId = RLP.encodeByte(this.networkId); - byte[] clientId = RLP.encodeString(this.clientId); - byte[] capabilities = RLP.encodeByte(this.capabilities); - byte[] peerPort = RLP.encodeShort(this.peerPort); - byte[] peerId = RLP.encodeElement(this.peerId); + byte[] command = RLP.encodeByte(HELLO.asByte()); + byte[] protocolVersion = RLP.encodeByte(this.protocolVersion); + byte[] networkId = RLP.encodeByte(this.networkId); + byte[] clientId = RLP.encodeString(this.clientId); + byte[] capabilities = RLP.encodeByte(this.capabilities); + byte[] peerPort = RLP.encodeShort(this.peerPort); + byte[] peerId = RLP.encodeElement(this.peerId); + byte[] totalDifficulty = RLP.encodeElement(this.totalDifficulty); + byte[] bestHash = RLP.encodeElement(this.bestHash); + byte[] genesisHash = RLP.encodeElement(this.genesisHash); - byte[] data = RLP.encodeList(command, protocolVersion, networkId, - clientId, capabilities, peerPort, peerId); + byte[] data = RLP.encodeList(command, protocolVersion, networkId, + clientId, capabilities, peerPort, peerId, totalDifficulty, + bestHash, genesisHash); return data; } @@ -116,14 +143,29 @@ public class HelloMessage extends Message { if (!parsed) parseRLP(); return peerId; } + + public byte[] getTotalDifficulty() { + if (!parsed) parseRLP(); + return totalDifficulty; + } - @Override + public byte[] getBestHash() { + if (!parsed) parseRLP(); + return bestHash; + } + + public byte[] getGenesisHash() { + if (!parsed) parseRLP(); + return genesisHash; + } + + @Override public String getMessageName() { return "HelloMessage"; } @Override - public Class getAnswerMessage() { + public Class getAnswerMessage() { return null; } @@ -136,6 +178,9 @@ public class HelloMessage extends Message { " capabilities=" + this.capabilities + " " + " peerPort=" + this.peerPort + " " + " peerId=" + Hex.toHexString(this.peerId) + " " + + " totalDifficulty=" + Hex.toHexString(this.totalDifficulty) + " " + + " bestHash=" + Hex.toHexString(this.bestHash) + " " + + " genesisHash=" + Hex.toHexString(this.genesisHash) + " " + "]"; } } diff --git a/ethereumj-core/src/main/java/org/ethereum/net/message/Message.java b/ethereumj-core/src/main/java/org/ethereum/net/message/Message.java index 8945f591..9be5c30c 100644 --- a/ethereumj-core/src/main/java/org/ethereum/net/message/Message.java +++ b/ethereumj-core/src/main/java/org/ethereum/net/message/Message.java @@ -20,12 +20,11 @@ public abstract class Message { parsed = false; } - public abstract void parseRLP(); - public abstract byte[] getPayload(); + public abstract void parseRLP(); - public abstract String getMessageName(); - - public abstract Class getAnswerMessage(); + public abstract byte[] getPayload(); + public abstract String getMessageName(); + public abstract Class getAnswerMessage(); } diff --git a/ethereumj-core/src/main/java/org/ethereum/net/message/NotInChainMessage.java b/ethereumj-core/src/main/java/org/ethereum/net/message/NotInChainMessage.java deleted file mode 100644 index 11c522c9..00000000 --- a/ethereumj-core/src/main/java/org/ethereum/net/message/NotInChainMessage.java +++ /dev/null @@ -1,58 +0,0 @@ -package org.ethereum.net.message; - -import static org.ethereum.net.Command.NOT_IN_CHAIN; - -import org.ethereum.net.Command; -import org.ethereum.net.message.Message; -import org.ethereum.util.RLPItem; -import org.ethereum.util.RLPList; -import org.spongycastle.util.encoders.Hex; - -/** - * www.ethereumJ.com - * @author: Roman Mandeleil - * Created on: 06/04/14 14:56 - */ -public class NotInChainMessage extends Message { - - private byte[] hash; - - public NotInChainMessage(RLPList rawData) { - super(rawData); - } - - @Override - public void parseRLP() { - RLPList paramsList = (RLPList) rawData.get(0); - - if (Command.fromInt(((RLPItem)(paramsList).get(0)).getRLPData()[0] & 0xFF) != NOT_IN_CHAIN) { - throw new Error("NotInChain Message: parsing for mal data"); - } - hash = ((RLPItem)paramsList.get(1)).getRLPData(); - } - - @Override - public byte[] getPayload() { - return null; - } - - public byte[] getHash() { - return hash; - } - - @Override - public String getMessageName() { - return "NotInChain"; - } - - @Override - public Class getAnswerMessage() { - return null; - } - - public String toString() { - if (!parsed) - parseRLP(); - return "NotInChain Message [" + Hex.toHexString(hash) + "]"; - } -} diff --git a/ethereumj-core/src/main/java/org/ethereum/net/message/ReasonCode.java b/ethereumj-core/src/main/java/org/ethereum/net/message/ReasonCode.java index b4858696..a5a5625b 100644 --- a/ethereumj-core/src/main/java/org/ethereum/net/message/ReasonCode.java +++ b/ethereumj-core/src/main/java/org/ethereum/net/message/ReasonCode.java @@ -3,9 +3,13 @@ package org.ethereum.net.message; import java.util.HashMap; import java.util.Map; +/** + * Reason is an optional integer specifying one + * of a number of reasons for disconnect + */ public enum ReasonCode { - DISCONNECT_REQUESTED(0x00), + REQUESTED(0x00), TCP_ERROR(0x01), BAD_PROTOCOL(0x02), USELESS_PEER(0x03), diff --git a/ethereumj-core/src/main/java/org/ethereum/net/message/StaticMessages.java b/ethereumj-core/src/main/java/org/ethereum/net/message/StaticMessages.java index bd229f11..54dcf6c4 100644 --- a/ethereumj-core/src/main/java/org/ethereum/net/message/StaticMessages.java +++ b/ethereumj-core/src/main/java/org/ethereum/net/message/StaticMessages.java @@ -1,7 +1,10 @@ package org.ethereum.net.message; import org.ethereum.config.SystemProperties; +import org.ethereum.core.Block; +import org.ethereum.core.Genesis; import org.ethereum.crypto.HashUtil; +import org.ethereum.manager.WorldManager; import org.spongycastle.util.encoders.Hex; /** @@ -11,21 +14,20 @@ import org.spongycastle.util.encoders.Hex; */ public class StaticMessages { - public final static GetTransactionsMessage - GET_TRANSACTIONS_MESSAGE = new GetTransactionsMessage(); - public final static GetPeersMessage GET_PEERS_MESSAGE = new GetPeersMessage(); public final static PingMessage PING_MESSAGE = new PingMessage(); public final static PongMessage PONG_MESSAGE = new PongMessage(); + public final static GetPeersMessage GET_PEERS_MESSAGE = new GetPeersMessage(); + public final static GetTransactionsMessage GET_TRANSACTIONS_MESSAGE = new GetTransactionsMessage(); - - public static final byte[] PING = Hex.decode("2240089100000002C102"); - public static final byte[] PONG = Hex.decode("2240089100000002C103"); - public static final byte[] GET_PEERS = Hex.decode("2240089100000002C110"); + 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[] MAGIC_PACKET = Hex.decode("22400891"); + public static final byte[] SYNC_TOKEN = Hex.decode("22400891"); + public static final byte[] GENESIS_HASH = Genesis.getInstance().getHash(); static { HELLO_MESSAGE = generateHelloMessage(); @@ -45,8 +47,12 @@ public class StaticMessages { String helloAnnouncement = String.format("Ethereum(J)/v%s/%s/%s/Java", version, phrase, system); + Block lastBlock = WorldManager.getInstance().getBlockchain().getLastBlock(); + byte[] totalDifficulty = lastBlock.getDifficulty(); + byte[] bestHash = lastBlock.getHash(); + return new HelloMessage((byte) 0x21, (byte) 0x00, helloAnnouncement, Byte.parseByte("00000111", 2), - (short) 30303, peerIdBytes); + (short) 30303, peerIdBytes, totalDifficulty, bestHash, GENESIS_HASH); } } diff --git a/ethereumj-core/src/main/java/org/ethereum/net/message/StatusMessage.java b/ethereumj-core/src/main/java/org/ethereum/net/message/StatusMessage.java new file mode 100644 index 00000000..a2cf8bd0 --- /dev/null +++ b/ethereumj-core/src/main/java/org/ethereum/net/message/StatusMessage.java @@ -0,0 +1,85 @@ +package org.ethereum.net.message; + +import static org.ethereum.net.Command.STATUS; + +import org.ethereum.util.RLP; +import org.ethereum.util.RLPItem; +import org.ethereum.util.RLPList; + +/** + * Wrapper around an Ethereum StatusMessage on the network + * + * @see {@link org.ethereum.net.Command#STATUS} + */ +public class StatusMessage extends Message { + + private byte protocolVersion; + private byte networkId; + + /** Total difficulty of the best chain as found in block header. */ + private byte[] totalDifficulty; + /** The hash of the best (i.e. highest TD) known block. */ + private byte[] bestHash; + /** The hash of the Genesis block */ + private byte[] genesisHash; + + public StatusMessage(RLPList rawData) { + super(rawData); + } + + public StatusMessage(byte protocolVersion, byte networkId, + byte[] totalDifficulty, byte[] bestHash, byte[] genesisHash) { + this.protocolVersion = protocolVersion; + this.networkId = networkId; + this.totalDifficulty = totalDifficulty; + this.bestHash = bestHash; + this.genesisHash = genesisHash; + this.parsed = true; + } + + @Override + public void parseRLP() { + + RLPList paramsList = (RLPList) rawData.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"); + + this.protocolVersion = ((RLPItem) paramsList.get(1)).getRLPData()[0]; + byte[] networkIdBytes = ((RLPItem) paramsList.get(2)).getRLPData(); + this.networkId = networkIdBytes == null ? 0 : networkIdBytes[0]; + this.totalDifficulty = ((RLPItem) paramsList.get(3)).getRLPData(); + this.bestHash = ((RLPItem) paramsList.get(4)).getRLPData(); + this.genesisHash = ((RLPItem) paramsList.get(5)).getRLPData(); + + this.parsed = true; + } + + @Override + public byte[] getPayload() { + byte[] command = RLP.encodeByte(STATUS.asByte()); + byte[] protocolVersion = RLP.encodeByte(this.protocolVersion); + byte[] networkId = RLP.encodeByte(this.networkId); + byte[] totalDifficulty = RLP.encodeElement(this.totalDifficulty); + byte[] bestHash = RLP.encodeElement(this.bestHash); + byte[] genesisHash = RLP.encodeElement(this.genesisHash); + + byte[] data = RLP.encodeList(command, protocolVersion, networkId, + totalDifficulty, bestHash, genesisHash); + + return data; + } + + @Override + public String getMessageName() { + return "StatusMessage"; + } + + @Override + public Class getAnswerMessage() { + return null; + } +} diff --git a/ethereumj-core/src/main/java/org/ethereum/net/message/TransactionsMessage.java b/ethereumj-core/src/main/java/org/ethereum/net/message/TransactionsMessage.java index 6fa947b2..067a8b6c 100644 --- a/ethereumj-core/src/main/java/org/ethereum/net/message/TransactionsMessage.java +++ b/ethereumj-core/src/main/java/org/ethereum/net/message/TransactionsMessage.java @@ -36,22 +36,20 @@ public class TransactionsMessage extends Message { for (Transaction tx : transactionList) { byte[] txPayload = tx.getEncoded(); - try { - baos.write(txPayload); - } catch (IOException e) { - logger.error(e.getMessage(), e); - } + 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) { + 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; @@ -66,9 +64,8 @@ public class TransactionsMessage extends Message { public void parseRLP() { RLPList paramsList = (RLPList) rawData.get(0); - if (Command.fromInt(((RLPItem)(paramsList).get(0)).getRLPData()[0] & 0xFF) != TRANSACTIONS) { - throw new Error("TransactionMessage: parsing for mal data"); - } + if (Command.fromInt(((RLPItem) (paramsList).get(0)).getRLPData()[0] & 0xFF) != TRANSACTIONS) + throw new Error("TransactionMessage: parsing for mal data"); transactions = new ArrayList(); int size = paramsList.size(); @@ -103,9 +100,8 @@ public class TransactionsMessage extends Message { public String toString() { if(!parsed) parseRLP(); StringBuffer sb = new StringBuffer(); - for (Transaction transaction : transactions) { + for (Transaction transaction : transactions) sb.append(" ").append(transaction).append("\n"); - } return "Transactions Message [\n" + sb.toString() + " ]"; } -} +} \ No newline at end of file diff --git a/ethereumj-core/src/main/java/org/ethereum/net/peerdiscovery/EthereumPeerTasterHandler.java b/ethereumj-core/src/main/java/org/ethereum/net/peerdiscovery/EthereumPeerTasterHandler.java index d8a66015..fc86b73a 100644 --- a/ethereumj-core/src/main/java/org/ethereum/net/peerdiscovery/EthereumPeerTasterHandler.java +++ b/ethereumj-core/src/main/java/org/ethereum/net/peerdiscovery/EthereumPeerTasterHandler.java @@ -145,15 +145,15 @@ public class EthereumPeerTasterHandler extends ChannelInboundHandlerAdapter { } private void sendPing(ChannelHandlerContext ctx) { - ByteBuf buffer = ctx.alloc().buffer(StaticMessages.PING.length); - buffer.writeBytes(StaticMessages.PING); + 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.length); - buffer.writeBytes(StaticMessages.PONG); + ByteBuf buffer = ctx.alloc().buffer(StaticMessages.PONG_PACKET.length); + buffer.writeBytes(StaticMessages.PONG_PACKET); ctx.writeAndFlush(buffer); } @@ -165,8 +165,8 @@ public class EthereumPeerTasterHandler extends ChannelInboundHandlerAdapter { } private void sendGetPeers(ChannelHandlerContext ctx) { - ByteBuf buffer = ctx.alloc().buffer(StaticMessages.GET_PEERS.length); - buffer.writeBytes(StaticMessages.GET_PEERS); + ByteBuf buffer = ctx.alloc().buffer(StaticMessages.GET_PEERS_PACKET.length); + buffer.writeBytes(StaticMessages.GET_PEERS_PACKET); ctx.writeAndFlush(buffer); } diff --git a/ethereumj-core/src/main/java/org/ethereum/vm/Program.java b/ethereumj-core/src/main/java/org/ethereum/vm/Program.java index 19130fd7..af3bb973 100644 --- a/ethereumj-core/src/main/java/org/ethereum/vm/Program.java +++ b/ethereumj-core/src/main/java/org/ethereum/vm/Program.java @@ -108,9 +108,8 @@ public class Program { this.pc = pc.intValue(); - if (this.pc == ops.length) { + if (this.pc == ops.length) stop(); - } if (this.pc > ops.length) { stop(); @@ -154,9 +153,8 @@ public class Program { } public DataWord stackPop() { - if (stack.size() == 0) { + if (stack.size() == 0) throw new EmptyStackException(); - } return stack.pop(); } @@ -174,9 +172,7 @@ public class Program { } public int getMemSize() { - int memSize = 0; - if (memory != null) memSize = memory.limit(); - return memSize; + return memory != null ? memory.limit() : 0; } public void memorySave(DataWord addrB, DataWord value) { @@ -361,7 +357,7 @@ public class Program { * That method is for internal code invocations * * - Normal calls invoke a specified contract which updates itself - * - Stateless calls invoke another contract, within the context of the caller + * - Stateless calls invoke code from another contract, within the context of the caller * * @param msg is the message call object */ @@ -452,11 +448,10 @@ public class Program { if (buffer != null && allocSize > 0) { int retSize = buffer.limit(); int offset = msg.getOutDataOffs().intValue(); - if (retSize > allocSize) { + if (retSize > allocSize) this.memorySave(offset, buffer.array()); - } else { + else this.memorySave(offset, allocSize, buffer.array()); - } } } @@ -609,10 +604,7 @@ public class Program { byte value = memory.get(i); // Check if value is ASCII - // (should be until 0x7e - but using 0x7f - // to be compatible with cpp-ethereum) - // See: https://github.com/ethereum/cpp-ethereum/issues/299 - String character = ((byte)0x20 <= value && value <= (byte)0x7f) ? new String(new byte[]{value}) : "?"; + String character = ((byte) 0x20 <= value && value <= (byte) 0x7e) ? new String(new byte[] { value }) : "?"; firstLine.append(character).append(""); secondLine.append(Utils.oneByteToHexString(value)).append(" "); @@ -706,21 +698,19 @@ public class Program { globalOutput.append(" -- MEMORY -- ").append(memoryData).append("\n"); globalOutput.append(" -- STORAGE -- ").append(storageData).append("\n"); - if (result.getHReturn() != null) { - globalOutput.append("\n HReturn: ").append(Hex.toHexString(result.getHReturn().array())); - } + if (result.getHReturn() != null) + globalOutput.append("\n HReturn: ").append( + Hex.toHexString(result.getHReturn().array())); - // soffisticated assumption that msg.data != codedata + // sophisticated assumption that msg.data != codedata // means we are calling the contract not creating it byte[] txData = invokeData.getDataCopy(DataWord.ZERO, getDataSize()); - if (!Arrays.equals(txData, ops)) { - globalOutput.append("\n msg.data: ").append(Hex.toHexString( txData )); - } + if (!Arrays.equals(txData, ops)) + globalOutput.append("\n msg.data: ").append(Hex.toHexString(txData)); globalOutput.append("\n\n Spent Gas: ").append(result.getGasUsed()); - if (listener != null) { + if (listener != null) listener.output(globalOutput.toString()); - } } } @@ -731,27 +721,25 @@ public class Program { OpCode op = OpCode.code(code[index]); byte[] continuedCode = null; - switch(op){ - case PUSH1: case PUSH2: case PUSH3: case PUSH4: case PUSH5: case PUSH6: case PUSH7: case PUSH8: - case PUSH9: case PUSH10: case PUSH11: case PUSH12: case PUSH13: case PUSH14: case PUSH15: case PUSH16: - case PUSH17: case PUSH18: case PUSH19: case PUSH20: case PUSH21: case PUSH22: case PUSH23: case PUSH24: - case PUSH25: case PUSH26: case PUSH27: case PUSH28: case PUSH29: case PUSH30: case PUSH31: case PUSH32: - result += ' ' + op.name() + ' '; - - int nPush = op.val() - OpCode.PUSH1.val() + 1; - byte[] data = Arrays.copyOfRange(code, index+1, index + nPush + 1); - result += new BigInteger(data).toString() + ' '; - - continuedCode = Arrays.copyOfRange(code, index + nPush + 1, code.length); - break; - - default: - result += ' ' + op.name(); - continuedCode = Arrays.copyOfRange(code, index + 1, code.length); - break; - + switch(op) { + case PUSH1: case PUSH2: case PUSH3: case PUSH4: case PUSH5: case PUSH6: case PUSH7: case PUSH8: + case PUSH9: case PUSH10: case PUSH11: case PUSH12: case PUSH13: case PUSH14: case PUSH15: case PUSH16: + case PUSH17: case PUSH18: case PUSH19: case PUSH20: case PUSH21: case PUSH22: case PUSH23: case PUSH24: + case PUSH25: case PUSH26: case PUSH27: case PUSH28: case PUSH29: case PUSH30: case PUSH31: case PUSH32: + result += ' ' + op.name() + ' '; + + int nPush = op.val() - OpCode.PUSH1.val() + 1; + byte[] data = Arrays.copyOfRange(code, index+1, index + nPush + 1); + result += new BigInteger(data).toString() + ' '; + + continuedCode = Arrays.copyOfRange(code, index + nPush + 1, code.length); + break; + + default: + result += ' ' + op.name(); + continuedCode = Arrays.copyOfRange(code, index + 1, code.length); + break; } - return stringify(continuedCode, 0, result); } diff --git a/ethereumj-core/src/test/java/org/ethereum/net/MessagesTest.java b/ethereumj-core/src/test/java/org/ethereum/net/MessagesTest.java index 21bfbb18..c941c241 100644 --- a/ethereumj-core/src/test/java/org/ethereum/net/MessagesTest.java +++ b/ethereumj-core/src/test/java/org/ethereum/net/MessagesTest.java @@ -26,6 +26,7 @@ import java.util.List; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; +import static org.junit.Assert.fail; public class MessagesTest { @@ -92,7 +93,7 @@ public class MessagesTest { DisconnectMessage disconnectMessage = new DisconnectMessage(rlpList); System.out.println(disconnectMessage); - assertEquals(disconnectMessage.getReason(), ReasonCode.DISCONNECT_REQUESTED); + assertEquals(disconnectMessage.getReason(), ReasonCode.REQUESTED); } @Test /* DisconnectMessage 2 */ @@ -323,47 +324,12 @@ public class MessagesTest { System.out.println(blocksMessage); } - /* GET_CHAIN */ + /* GET_BLOCKS */ - @Test /* GET_CHAIN message parsing*/ + @Test /* GET_BLOCKS message parsing*/ public void test_12() { - String getChainRaw = "F9042414A09F7A910147A6C99AB7EEEAC1ADC7B1B9B0D7D9DD83FD7FC125561016F19B624DA024B519ED5F71207330C1F450B7A4C7445C589B5F9AE73E9BBA09E0A8CB15D845A01EF7B03C7E58E65068D71F68E168C0CC0438808C32FB3E46E402D078B2020E0DA06A0F152620F606E134679D22A86156F9DDEB56FACD62C3106CC66AE030234483A001A3E918F9C2F74BD144505CF70650EF30BE806C533BA5AE3C983F55615EE98EA0E5E441F0877116011CCDECE2501A50B40C40418377037E16D0282B2B5E347138A0C55035BC5BDA25A8C6A2EFF4CCF5386CFFF3E7EE1DC9168B00AABF1074FEB1E2A060AC4D0C12C4CBF552440E659FE4E54C38EF7D05EF98965BA0E0248379CB78DFA0E1620BF60A735DDEA7CB434143E7EF663D043420F017360289FF78046948A77AA0DA8BC25F6571AB0EDE9C3DEF34FFF996575ADFCC1F8009A0388CE0A63AD9FC57A0E153CD998421E4F6BAC6A8329AE90BDA70D5D0F46A7EC02B88BDF5D3CAA8384FA0D3F00977D766A5CAF8F07EF8D15B1DADBBFD57B60BBE6CA54B2F9C2446F614EFA08687EC7AE1A541B13CDA57DCF387DEA3EA35A35AC3D5A9381376EAFBC7BA2CF5A08814AC8660E776A3FCA432D2E9A3533AFFEAEC783ECBB5DAD495B44E04EF1F98A07F2E67F508830BF18E8A432BAB9B957FA2BCDE57BE6C766C13871F833C27B9A5A021EE1E6602530EF711F6C8022799108E1AFB546E7B5FF3E3CBB4DA66C054868DA02940A17DD5C1D1911FFDA7DFAE3E5FAF8E1808CBD11F3248C18B8777B4A5D256A07E5D2F25D9750665ADBFF9C36820AD67CC55850D7D798DAB512343AB0C4E58B3A06674BD13B1051852413031BAA885448E50917D7F1D5EFB7DBA397ED4E5C36D72A06AA7A7D18B07BE0222DA47A8EE6923BAD522DBF5D0650D64CA0F2AD4C606D0CCA07F877735FCC29F804926AACEDBF7AD4896E330DCCE57F257A7D5C81F5CC03188A0FF6B7749526281A5E6A845B8ACC7DC03D2CAAEAFF0CEBF78659FDE1007AD9C05A054D6375CF54B0246FB45787206BA70115DED577354942A9219BC9E761A7E0CBCA0809384946576FB15A8F827B30045D18203A90BE662863D5F205B868DF882472AA05A6EA58D02A2823BA693AC11C21D3C4D66AFFFDB9F1475EA86A461912C2F3187A003AF21F3939C29C231200B1F790F16421A8923254CBF2A90455B9B8F28BE4562A036FDFB3E05936CAA1ABBDCFBBACD9000F86FBCAE2228E77346533CEF17073767A0D3CE8B71E129020F3356A09946F9BC4C18E61D9516E74F6F912461A438F1E006A01D8203A8E23F50D70188ED3099E50645B92959C2216EA7A74719C159B4978BDBA03812A8FC4A5BB6EF0832EBF5058FAF65A46187CEE568C94915AE1850069775F3A0687DDEF8750F606637B3F5F23D286053671081A1AD224B35A624DE7392193951A0E6A8E1D4417292E20F9698A3464CEEABC6476A57521FF79D994DE22C55DADEAD820100"; - - byte[] payload = Hex.decode(getChainRaw); - RLPList rlpList = RLP.decode2(payload); - - GetChainMessage getChainMessage = new GetChainMessage(rlpList); - getChainMessage.parseRLP(); - System.out.println(getChainMessage); - - assertEquals(32, getChainMessage.getBlockHashList().size()); - - assertEquals("E5E441F0877116011CCDECE2501A50B40C40418377037E16D0282B2B5E347138", - Hex.toHexString( getChainMessage.getBlockHashList().get(5) ).toUpperCase()); - - assertEquals("6AA7A7D18B07BE0222DA47A8EE6923BAD522DBF5D0650D64CA0F2AD4C606D0CC", - Hex.toHexString( getChainMessage.getBlockHashList().get(19) ).toUpperCase()); - - assertEquals("03AF21F3939C29C231200B1F790F16421A8923254CBF2A90455B9B8F28BE4562", - Hex.toHexString( getChainMessage.getBlockHashList().get(25) ).toUpperCase()); - } - - /* NOT_IN_CHAIN */ - - @Test /* NotInChainMessage parsing 1 */ - public void test_13() { - - String getChainRaw = "E015A0E5E441F0877116011CCDECE2501A50B40C40418377037E16D0282B2B5E347138"; - - byte[] payload = Hex.decode(getChainRaw); - RLPList rlpList = RLP.decode2(payload); - - NotInChainMessage notInChainMessage = new NotInChainMessage(rlpList); - System.out.println(notInChainMessage); - - assertEquals("E5E441F0877116011CCDECE2501A50B40C40418377037E16D0282B2B5E347138", - Hex.toHexString(notInChainMessage.getHash()).toUpperCase()); + fail("Not yet implemented"); } @Test /* BlocksMessage POC-5 real msg*/ @@ -396,23 +362,10 @@ public class MessagesTest { Block block = list.get(0); } - @Test /* GetChain encode */ + @Test /* GetBlocks encode */ public void test14() { - String expected = "F86514A0B4986B41E57B351FD037775A4D439443B4BDE859D061D772117AFA855BFDE18EA0241A2A72372AD63C40704C93CD380A51FEE174EB59501D731A009F51372E5205A0E963653D860F35E27A5572CFEECE1BB518C42BB97DEAC0978FA788F6DCB45CF764"; - - String hash1 = "B4986B41E57B351FD037775A4D439443B4BDE859D061D772117AFA855BFDE18E"; - String hash2 = "241A2A72372AD63C40704C93CD380A51FEE174EB59501D731A009F51372E5205"; - String hash3 = "E963653D860F35E27A5572CFEECE1BB518C42BB97DEAC0978FA788F6DCB45CF7"; - - GetChainMessage getChainMessage = - new GetChainMessage((byte)100, Hex.decode(hash1), Hex.decode(hash2), Hex.decode(hash3)); - - assertEquals(expected, Hex.toHexString(getChainMessage.getPayload()).toUpperCase()); - - byte[] size = ByteUtil.calcPacketLength( getChainMessage.getPayload()); - - assertEquals("00000067", Hex.toHexString(size)); + fail("Not yet implemented"); } @Test /* Transactions msg encode */ @@ -441,9 +394,6 @@ public class MessagesTest { assertEquals(expected, Hex.toHexString( transactionsMessage.getPayload()) ); } - - - @Ignore @Test /* Block msg decode - found bug tool */ public void test17() throws URISyntaxException, IOException { diff --git a/ethereumj-core/src/test/resources/system.properties b/ethereumj-core/src/test/resources/system.properties index a97eb370..6c1e967d 100644 --- a/ethereumj-core/src/test/resources/system.properties +++ b/ethereumj-core/src/test/resources/system.properties @@ -6,25 +6,26 @@ server.acceptConnections = false # the search of the online peers # values: [ip:port, ip:port, ip:port ...] peer.discovery.ip.list = 185.43.109.23:30303, \ - 54.211.14.10:30303, \ - 213.100.248.181:30303, \ - 54.72.69.180:30303, \ - 54.201.28.117:30303, \ - 70.29.74.8:7 + 207.12.89.101:30303 + +#peer.discovery.ip.list = 127.0.0.1:30303 # active peer ip and port # that is the peer through # we get the chain: [54.201.28.117] port: [30303] # ZeroGox -peer.active.ip = 54.204.10.41 +#peer.active.ip = 54.204.10.41 +#peer.active.port = 30303 + +#peer.active.ip = 185.43.109.23 +#peer.active.port = 30303 + +# PoC-6 testnet +peer.active.ip = 207.12.89.101 peer.active.port = 30303 -# RomanJ -#peer.active.ip = 54.211.14.10 -#peer.active.port = 50505 - -# PoC-5 testnet -#peer.active.ip = 54.72.69.180 +# Localhost +#peer.active.ip = 127.0.0.1 #peer.active.port = 30303 # specify if the mechanism @@ -119,4 +120,4 @@ project.version = PROJECT.VERSION # hello phrase will be included in # the hello message of the peer -hello.phrase = RJ \ No newline at end of file +hello.phrase = \ No newline at end of file diff --git a/ethereumj-studio/src/main/java/org/ethereum/gui/ToolBar.java b/ethereumj-studio/src/main/java/org/ethereum/gui/ToolBar.java index 53929e94..a7c60b45 100644 --- a/ethereumj-studio/src/main/java/org/ethereum/gui/ToolBar.java +++ b/ethereumj-studio/src/main/java/org/ethereum/gui/ToolBar.java @@ -42,7 +42,7 @@ public class ToolBar extends JFrame { String version = SystemProperties.CONFIG.projectVersion(); introLogger.info(""); - introLogger.info("|Ξ| EthereumJ [v" + version + "] by RomanJ"); + introLogger.info("|Ξ| EthereumJ [v" + version + "]"); introLogger.info("|Ξ| Code by Roman Mandeleil, (c) 2014."); introLogger.info("|Ξ| Contribution: Nick Savers "); introLogger.info("|Ξ| Based on a design by Vitalik Buterin."); diff --git a/ethereumj-studio/src/main/resources/system.properties b/ethereumj-studio/src/main/resources/system.properties index 677e7454..f24f017a 100644 --- a/ethereumj-studio/src/main/resources/system.properties +++ b/ethereumj-studio/src/main/resources/system.properties @@ -6,11 +6,8 @@ server.acceptConnections = false # the search of the online peers # values: [ip:port, ip:port, ip:port ...] peer.discovery.ip.list = 185.43.109.23:30303, \ - 54.211.14.10:30303, \ - 213.100.248.181:30303, \ - 54.72.69.180:30303, \ - 54.201.28.117:30303, \ - 70.29.74.8:7 + 207.12.89.101:30303 + #peer.discovery.ip.list = 127.0.0.1:30303 # active peer ip and port @@ -20,31 +17,17 @@ peer.discovery.ip.list = 185.43.109.23:30303, \ #peer.active.ip = 54.204.10.41 #peer.active.port = 30303 -# Some dude in Canada -#peer.active.ip = 131.104.247.135 -#peer.active.port = 30303 - -# RomanJ -peer.active.ip = 54.211.14.10 -peer.active.port = 30303 - -# PoC-5 testnet #peer.active.ip = 185.43.109.23 #peer.active.port = 30303 +# PoC-6 testnet +peer.active.ip = 207.12.89.101 +peer.active.port = 30303 + # Localhost #peer.active.ip = 127.0.0.1 #peer.active.port = 30303 -#peer.active.ip = 54.72.69.180 -#peer.active.port = 30303 - -#peer.active.ip = 185.43.109.23 -#peer.active.port = 30303 - -#peer.active.ip = 151.64.223.120 -#peer.active.port = 30304 - # specify if the mechanism # to discover more and more # peers and check the already @@ -146,4 +129,4 @@ project.version = PROJECT.VERSION # hello phrase will be included in # the hello message of the peer -hello.phrase = RJ \ No newline at end of file +hello.phrase = \ No newline at end of file