Downloading the full block chain, and a first model for the chain table
dialog.
This commit is contained in:
parent
c1d619bc92
commit
2a037eb5db
|
@ -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() {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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[]){
|
||||
|
|
|
@ -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) {}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -11,6 +11,7 @@ public abstract class Message {
|
|||
|
||||
RLPList rawData;
|
||||
boolean parsed = false;
|
||||
byte[] payload;
|
||||
|
||||
public Message() {}
|
||||
|
||||
|
|
|
@ -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 " +
|
||||
|
|
|
@ -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
Loading…
Reference in New Issue