Downloading the full block chain, and a first model for the chain table

dialog.
This commit is contained in:
romanman 2014-05-15 15:55:05 +03:00
parent c1d619bc92
commit 2a037eb5db
16 changed files with 361 additions and 35 deletions

View File

@ -111,7 +111,7 @@ public class Block {
RLPList params = (RLPList) rawData.get(0);
this.hash = HashUtil.sha3(params.getRLPData());
this.hash = HashUtil.sha3(rawData.getRLPData());
this.parentHash = ((RLPItem) params.get(0)).getData();
@ -284,8 +284,8 @@ public class Block {
}
public byte[] getEncoded() {
if (this.encodedBlock == null) parseRLP();
return this.encodedBlock;
if (this.rawData.getRLPData() == null) parseRLP();
return this.rawData.getRLPData();
}
public byte[] hash() {

View File

@ -70,24 +70,27 @@ public class Transaction {
}
public void rlpParse(){
this.hash = HashUtil.sha3(rawData.getRLPData());
this.nonce = ((RLPItem) rawData.get(0)).getData();
this.value = ((RLPItem) rawData.get(1)).getData();
this.receiveAddress = ((RLPItem) rawData.get(2)).getData();
this.gasPrice = ((RLPItem) rawData.get(3)).getData();
this.gasLimit = ((RLPItem) rawData.get(4)).getData();
this.data = ((RLPItem) rawData.get(5)).getData();
if (rawData.size() == 9){ // Simple transaction
byte v = ((RLPItem) rawData.get(6)).getData()[0];
byte[] r = ((RLPItem) rawData.get(7)).getData();
byte[] s = ((RLPItem) rawData.get(8)).getData();
RLPList params = (RLPList) rawData.get(0);
this.hash = HashUtil.sha3(rawData.getRLPData());
this.nonce = ((RLPItem) params.get(0)).getData();
this.value = ((RLPItem) params.get(1)).getData();
this.receiveAddress = ((RLPItem) params.get(2)).getData();
this.gasPrice = ((RLPItem) params.get(3)).getData();
this.gasLimit = ((RLPItem) params.get(4)).getData();
this.data = ((RLPItem) params.get(5)).getData();
if (params.size() == 9){ // Simple transaction
byte v = ((RLPItem) params.get(6)).getData()[0];
byte[] r = ((RLPItem) params.get(7)).getData();
byte[] s = ((RLPItem) params.get(8)).getData();
this.signature = ECDSASignature.fromComponents(r, s, v);
} else if (rawData.size() == 10){ // Contract creation transaction
this.init = ((RLPItem) rawData.get(6)).getData();
byte v = ((RLPItem) rawData.get(7)).getData()[0];
byte[] r = ((RLPItem) rawData.get(8)).getData();
byte[] s = ((RLPItem) rawData.get(9)).getData();
} else if (params.size() == 10){ // Contract creation transaction
this.init = ((RLPItem) params.get(6)).getData();
byte v = ((RLPItem) params.get(7)).getData()[0];
byte[] r = ((RLPItem) params.get(8)).getData();
byte[] s = ((RLPItem) params.get(9)).getData();
this.signature = ECDSASignature.fromComponents(r, s, v);
} else throw new RuntimeException("Wrong tx data element list size");
this.parsed = true;

View File

@ -0,0 +1,73 @@
package org.ethereum.gui;
import javax.swing.*;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.TableCellRenderer;
import java.awt.*;
/**
* www.ethereumJ.com
* User: Roman Mandeleil
* Created on: 15/05/14 12:36
*/
public class BlockChainTable extends JFrame {
private JPanel topPanel;
private JTable table;
private JScrollPane scrollPane;
public BlockChainTable() {
setTitle("Block Chain Table");
setSize(700, 400);
setLocation(315, 180);
setBackground(Color.gray);
java.net.URL url = ClassLoader.getSystemResource("ethereum-icon.png");
Toolkit kit = Toolkit.getDefaultToolkit();
Image img = kit.createImage(url);
this.setIconImage(img);
// Create a panel to hold all other components
topPanel = new JPanel();
topPanel.setLayout(new BorderLayout());
getContentPane().add(topPanel);
// Create a new table instance
table = new JTable();
table.setModel(new BlockTableModel());
table.setFont(new Font("Courier New", Font.PLAIN, 13));
table.setForeground(Color.GRAY);
table.setTableHeader(null);
TableCellRenderer tcr = table.getDefaultRenderer(String.class);
DefaultTableCellRenderer renderer = (DefaultTableCellRenderer) tcr;
renderer.setHorizontalAlignment(SwingConstants.LEFT);
renderer.setVerticalAlignment(SwingConstants.TOP);
table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
table.setCellSelectionEnabled(true);
table.setRowMargin(3);
table.setRowHeight(120);
table.getColumnModel().getColumn(0).setCellRenderer(new TableCellLongTextRenderer());
// Add the table to a scrolling pane
scrollPane = new JScrollPane(table);
topPanel.add(scrollPane, BorderLayout.CENTER);
}
public static void main(String args[]){
BlockChainTable mainFrame = new BlockChainTable();
mainFrame.setVisible(true);
mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}

View File

@ -0,0 +1,38 @@
package org.ethereum.gui;
import org.ethereum.manager.MainData;
import org.spongycastle.util.encoders.Hex;
import javax.swing.table.AbstractTableModel;
/**
* www.ethereumJ.com
* User: Roman Mandeleil
* Created on: 15/05/14 12:42
*/
public class BlockTableModel extends AbstractTableModel {
@Override
public int getRowCount() {
fireTableDataChanged();
int rowCount = MainData.instance.getAllBlocks().size();
return rowCount;
}
@Override
public int getColumnCount() {
return 1;
}
@Override
public Object getValueAt(int rowIndex, int columnIndex) {
// byte[] hash = MainData.instance.getAllBlocks().get(rowIndex).getHash();
// return Hex.toHexString(hash);
return MainData.instance.getAllBlocks().get(rowIndex).toString();
}
}

View File

@ -62,10 +62,10 @@ public class ConnectionConsole extends JFrame implements PeerListener{
Thread t = new Thread() {
public void run() {
new ClientPeer(thisConsole).connect("localhost", 30303);
// new ClientPeer(thisConsole).connect("82.217.72.169", 30303);
// new ClientPeer(thisConsole).connect("54.201.28.117", 30303);
// new ClientPeer(thisConsole).connect("82.217.72.169", 30303);
// new ClientPeer(thisConsole).connect("54.204.10.41", 30303);
new ClientPeer(thisConsole).connect("54.204.10.41", 30303);
}
};
t.start();

View File

@ -0,0 +1,47 @@
package org.ethereum.gui;
import java.awt.*;
import javax.swing.*;
import javax.swing.border.Border;
import javax.swing.border.EmptyBorder;
import javax.swing.table.TableCellRenderer;
/**
* www.ethereumJ.com
* User: Roman Mandeleil
* Created on: 15/05/14 13:08
*/
public class TableCellLongTextRenderer extends JTextArea implements TableCellRenderer{
protected static Border m_noFocusBorder;
public TableCellLongTextRenderer() {
m_noFocusBorder = new EmptyBorder(1, 2, 1, 2);
setOpaque(true);
setBorder(m_noFocusBorder);
}
@Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
this.setText((String) value);
this.setSelectedTextColor(Color.BLUE);
this.setWrapStyleWord(true);
this.setLineWrap(true);
setBackground(isSelected && !hasFocus ? table.getSelectionBackground() : table.getBackground());
setForeground(isSelected && !hasFocus ? table.getSelectionForeground() : table.getForeground());
setBorder(hasFocus? UIManager.getBorder("Table.focusCellHighlightBorder") : m_noFocusBorder);
//set the JTextArea to the width of the table column
setSize(table.getColumnModel().getColumn(column).getWidth(), getPreferredSize().height);
if (table.getRowHeight(row) != getPreferredSize().height) {
//set the height of the table row to the calculated height of the JTextArea
table.setRowHeight(row, getPreferredSize().height);
}
return this;
}
}

View File

@ -21,7 +21,7 @@ public class ToolBar extends JFrame {
Toolkit kit = Toolkit.getDefaultToolkit();
Image img = kit.createImage(url);
this.setIconImage(img);
this.setSize(350, 130);
this.setSize(350, 200);
this.setLocation(460, 25);
this.setAlwaysOnTop(true);
this.setResizable(false);
@ -41,6 +41,13 @@ public class ToolBar extends JFrame {
java.net.URL imageURL_3 = ClassLoader.getSystemResource("buttons/browser.png");
ImageIcon image_3 = new ImageIcon(imageURL_3);
java.net.URL imageURL_4 = ClassLoader.getSystemResource("buttons/shazam.png");
ImageIcon image_4 = new ImageIcon(imageURL_4);
java.net.URL imageURL_5 = ClassLoader.getSystemResource("buttons/wallet.png");
ImageIcon image_5 = new ImageIcon(imageURL_5);
JToggleButton editorToggle = new JToggleButton("");
editorToggle.setIcon(image_1);
editorToggle.setContentAreaFilled(true);
@ -96,9 +103,37 @@ public class ToolBar extends JFrame {
}
});
JToggleButton chainToggle = new JToggleButton();
chainToggle.setIcon(image_4);
chainToggle.setToolTipText("Block Chain");
chainToggle.setContentAreaFilled(true);
chainToggle.setBackground(Color.WHITE);
chainToggle.setBorderPainted(false);
chainToggle.setFocusPainted(false);
chainToggle.setCursor(new Cursor(Cursor.HAND_CURSOR));
chainToggle.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
BlockChainTable mainFrame = new BlockChainTable();
mainFrame.setVisible(true);
// mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
});
JToggleButton walletToggle = new JToggleButton();
walletToggle.setIcon(image_5);
walletToggle.setToolTipText("Wallet");
walletToggle.setContentAreaFilled(true);
walletToggle.setBackground(Color.WHITE);
walletToggle.setBorderPainted(false);
walletToggle.setFocusPainted(false);
walletToggle.setCursor(new Cursor(Cursor.HAND_CURSOR));
cp.add(editorToggle);
cp.add(logToggle);
cp.add(peersToggle);
cp.add(chainToggle);
cp.add(walletToggle);
}
public static void main(String args[]){

View File

@ -6,6 +6,8 @@ import org.ethereum.core.Block;
import org.ethereum.core.Transaction;
import org.ethereum.geodb.IpGeoDB;
import org.ethereum.net.client.PeerData;
import org.ethereum.net.message.StaticMessages;
import org.spongycastle.util.encoders.Hex;
import java.util.*;
@ -16,10 +18,16 @@ import java.util.*;
*/
public class MainData {
private Set<PeerData> peers = Collections.synchronizedSet(new HashSet<PeerData>());
private List<Block> blockChainDB = new ArrayList<Block>();
public static MainData instance = new MainData();
public MainData() {
}
public void addPeers(List<PeerData> newPeers){
this.peers.addAll(newPeers);
for (PeerData peerData : this.peers){
@ -30,6 +38,52 @@ public class MainData {
}
}
public void addBlocks(List<Block> blocks) {}
public void addBlocks(List<Block> blocks) {
// TODO: redesign this part when the state part and the genesis block is ready
Block firstBlockToAdd = blocks.get(blocks.size() - 1);
// if it is the first block to add
// check that the parent is the genesis
if (blockChainDB.isEmpty() &&
!"69a7356a245f9dc5b865475ada5ee4e89b18f93c06503a9db3b3630e88e9fb4e".
equals(Hex.toHexString(firstBlockToAdd.getParentHash()))){
return;
}
// if there is some blocks allready
// keep chain continuity
if (!blockChainDB.isEmpty() ){
Block lastBlock = blockChainDB.get(blockChainDB.size() - 1);
String hashLast = Hex.toHexString(lastBlock.getHash());
String blockParentHash = Hex.toHexString(firstBlockToAdd.getParentHash());
if (!hashLast.equals(blockParentHash)) return;
}
for (int i = blocks.size() - 1; i > 0 ; --i){
blockChainDB.add(blocks.get(i));
}
System.out.println("*** Block chain size: [" + blockChainDB.size() + "]");
}
public byte[] getLatestBlockHash(){
if (blockChainDB.isEmpty())
return StaticMessages.GENESSIS_HASH;
else
return blockChainDB.get(blockChainDB.size() - 1).hash();
}
public List<Block> getAllBlocks(){
return blockChainDB;
}
public void addTransactions(List<Transaction> transactions) {}
}

View File

@ -108,7 +108,7 @@ public class EthereumProtocolHandler extends ChannelInboundHandlerAdapter {
System.out.println("[Send: GET_CHAIN]");
sendGetChain(ctx);
}
}, 10000);
}, 10000, 10000);
/*
timer.schedule(new TimerTask() {
@ -304,8 +304,15 @@ public class EthereumProtocolHandler extends ChannelInboundHandlerAdapter {
}
private void sendGetChain(ChannelHandlerContext ctx){
ByteBuf buffer = ctx.alloc().buffer(StaticMessages.GET_CHAIN.length);
buffer.writeBytes(StaticMessages.GET_CHAIN);
byte[] hash = MainData.instance.getLatestBlockHash();
GetChainMessage chainMessage = new GetChainMessage((byte)100, hash);
ByteBuf buffer = ctx.alloc().buffer(chainMessage.getPayload().length + 8);
buffer.writeBytes(StaticMessages.MAGIC_PACKET);
buffer.writeBytes(Utils.calcPacketSize(chainMessage.getPayload()));
buffer.writeBytes(chainMessage.getPayload());
ctx.writeAndFlush(buffer);
}

View File

@ -7,9 +7,11 @@ 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.ethereum.util.Utils;
import org.spongycastle.util.encoders.Hex;
/**
* www.ethereumJ.com
@ -25,6 +27,23 @@ public class GetChainMessage extends Message {
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){
byte[] element = RLP.encodeElement(hash);
encodedElements[i] = element;
++i;
}
encodedElements[i] = RLP.encodeByte(number);
this.payload = RLP.encodeList(encodedElements);
}
@Override
public void parseRLP() {
@ -49,7 +68,7 @@ public class GetChainMessage extends Message {
@Override
public byte[] getPayload() {
return null;
return payload;
}
public List<byte[]> getBlockHashList() {

View File

@ -11,6 +11,7 @@ public abstract class Message {
RLPList rawData;
boolean parsed = false;
byte[] payload;
public Message() {}

View File

@ -1,6 +1,7 @@
package org.ethereum.net.message;
import org.ethereum.util.Utils;
import org.spongycastle.util.encoders.Hex;
/**
* www.ethereumJ.com
@ -46,14 +47,10 @@ public class StaticMessages {
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x03,
(byte) 0xC2, (byte) 0x01, (byte) 0x08};
public static final byte[] GET_CHAIN = {
(byte) 0x22, (byte) 0x40, (byte) 0x08, (byte) 0x91, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x27,
(byte) 0xF8, (byte) 0x25, (byte) 0x14, (byte) 0xA0, (byte) 0xAB, (byte) 0x6B, (byte) 0x9A, (byte) 0x56, (byte) 0x13,
(byte) 0x97, (byte) 0x0F, (byte) 0xAA, (byte) 0x77, (byte) 0x1B, (byte) 0x12, (byte) 0xD4, (byte) 0x49,
(byte) 0xB2, (byte) 0xE9, (byte) 0xBB, (byte) 0x92, (byte) 0x5A, (byte) 0xB7, (byte) 0xA3, (byte) 0x69,
(byte) 0xF0, (byte) 0xA4, (byte) 0xB8, (byte) 0x6B, (byte) 0x28, (byte) 0x6E, (byte) 0x9D, (byte) 0x54,
(byte) 0x00, (byte) 0x99, (byte) 0xCF, (byte) 0x82, (byte) 0x01, (byte) 0x00,
};
public static final byte[] GET_CHAIN = Hex.decode("2240089100000027F82514A069A7356A245F9DC5B865475ADA5EE4E89B18F93C06503A9DB3B3630E88E9FB4E820100");
public static final byte[] GENESSIS_HASH = Hex.decode("69a7356a245f9dc5b865475ada5ee4e89b18f93c06503a9db3b3630e88e9fb4e");
public static final byte[] MAGIC_PACKET = Hex.decode("22400891");
static {
String peerId = "CE 73 F1 F1 F1 F1 6C 1B 3F DA 7B 18 EF 7B A3 CE " +

View File

@ -78,4 +78,17 @@ public class Utils {
ImageIcon image = new ImageIcon(imageURL);
return image;
}
// The packet size should be 4 byte long
public static byte[] calcPacketSize(byte[] packet){
byte[] size = new byte[4];
size[3] = (byte)(packet.length >> 0 & 0xFF);
size[2] = (byte)(packet.length >> 8 & 0xFF);
size[1] = (byte)(packet.length >> 16 & 0xFF);
size[0] = (byte)(packet.length >> 24 & 0xFF);
return size;
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

File diff suppressed because one or more lines are too long