Add new address to a GUI wallet

This commit is contained in:
romanman 2014-05-18 18:49:16 +03:00
parent e7b2fd7d19
commit 7affbd26c8
18 changed files with 443 additions and 36 deletions

View File

@ -0,0 +1,48 @@
package org.ethereum.core;
import org.ethereum.crypto.ECKey;
import org.ethereum.crypto.HashUtil;
import org.ethereum.util.Utils;
import org.spongycastle.util.encoders.Hex;
import java.math.BigInteger;
import java.util.Arrays;
/**
* www.ethereumJ.com
* User: Roman Mandeleil
* Created on: 17/05/14 19:10
*/
public class Address {
byte[] privKey;
byte[] pubKey;
public Address(){
privKey = new BigInteger(130, Utils.getRandom()).toString(32).getBytes();
this.pubKey = ECKey.fromPrivate(privKey).getAddress();
}
public Address(byte[] privKey) {
this.privKey = privKey;
this.pubKey = ECKey.fromPrivate(privKey).getAddress();
}
public Address(byte[] privKey, byte[] pubKey) {
this.privKey = privKey;
this.pubKey = pubKey;
}
public byte[] getPrivKey() {
return privKey;
}
public byte[] getPubKey() {
return pubKey;
}
@Override
public String toString() {
return Hex.toHexString(pubKey);
}
}

View File

@ -0,0 +1,156 @@
package org.ethereum.core;
import org.w3c.dom.Attr;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import java.io.File;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Set;
/**
* www.ethereumJ.com
* User: Roman Mandeleil
* Created on: 17/05/14 15:53
*/
public class Wallet {
HashMap<Address, BigInteger> rows = new HashMap<>();
List<WalletListener> listeners = new ArrayList();
int high;
public void addNewKey(){
Address address = new Address();
rows.put(address, BigInteger.ZERO);
for (WalletListener listener : listeners) listener.valueChanged();
}
public void importKey(byte[] privKey){
Address address = new Address(privKey);
rows.put(address, BigInteger.ZERO);
notifyListeners();
}
public void addListener(WalletListener walletListener){
this.listeners.add(walletListener);
}
public Set<Address> getAddressSet(){
return rows.keySet();
}
public BigInteger getBalance(Address address){
return rows.get(address);
}
public BigInteger totalBalance(){
BigInteger sum = BigInteger.ZERO;
for (BigInteger value : rows.values()){
sum = sum.add(value);
}
return sum;
}
/**
* Load wallet file from the disk
*/
public void load() {
}
/**
* Save wallet file to the disk
*/
public void save() throws ParserConfigurationException, ParserConfigurationException, TransformerException {
/**
<wallet high="8933">
<row id=1>
<address>7c63d6d8b6a4c1ec67766ae123637ca93c199935<address/>
<privkey>roman<privkey/>
<value>20000000<value/>
</row>
<row id=2>
<address>b5da3e0ba57da04f94793d1c334e476e7ce7b873<address/>
<privkey>cow<privkey/>
<value>900099909<value/>
</row>
</wallet>
*/
String dir = System.getProperty("user.dir");
String fileName = dir + "/wallet.xml";
DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
Document doc = docBuilder.newDocument();
Element walletElement = doc.createElement("wallet");
doc.appendChild(walletElement);
Attr high = doc.createAttribute("high");
high.setValue("2345");
walletElement.setAttributeNode(high);
// staff elements
Element raw = doc.createElement("raw");
Attr id = doc.createAttribute("id");
id.setValue("1");
raw.setAttributeNode(id);
Element address = doc.createElement("address");
address.setTextContent("732f3b4b6cf31f5d14fed3a5f24f6e90ae6db2cc");
Element privKey = doc.createElement("privkey");
privKey.setTextContent("caw");
Element value = doc.createElement("value");
value.setTextContent("200000000000000");
raw.appendChild(address);
raw.appendChild(privKey);
raw.appendChild(value);
walletElement.appendChild(raw);
// write the content into xml file
TransformerFactory transformerFactory = TransformerFactory.newInstance();
Transformer transformer = transformerFactory.newTransformer();
DOMSource source = new DOMSource(doc);
StreamResult result = new StreamResult(new File(fileName));
// Output to console for testing
// StreamResult result = new StreamResult(System.out);
transformer.transform(source, result);
}
private void notifyListeners(){
for (WalletListener listener : listeners) listener.valueChanged();
}
public interface WalletListener{
public void valueChanged();
}
}

View File

@ -219,7 +219,7 @@ public class ECKey implements Serializable {
public byte[] getAddress() {
if (pubKeyHash == null) {
byte[] pubBytes = this.pub.getEncoded(false);
pubKeyHash = HashUtil.sha3hash160(Arrays.copyOfRange(pubBytes, 1, pubBytes.length));
pubKeyHash = HashUtil.sha3omit12(Arrays.copyOfRange(pubBytes, 1, pubBytes.length));
}
return pubKeyHash;
}

View File

@ -2,10 +2,13 @@ package org.ethereum.crypto;
import static java.util.Arrays.copyOfRange;
import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import org.ethereum.util.ByteUtil;
import org.ethereum.util.Utils;
import org.spongycastle.util.encoders.Hex;
public class HashUtil {
@ -34,7 +37,7 @@ public class HashUtil {
/**
* Calculates RIGTMOST160(SHA3(input)). This is used in address calculations.
*/
public static byte[] sha3hash160(byte[] input) {
public static byte[] sha3omit12(byte[] input) {
byte[] hash = sha3(input);
return copyOfRange(hash, 12, hash.length);
}
@ -58,4 +61,21 @@ public class HashUtil {
return sha256digest.digest(first);
}
}
/**
* @return generates random peer id for the HelloMessage
*/
public static byte[] randomPeerId(){
byte[] peerIdBytes = new BigInteger(512, Utils.getRandom()).toByteArray();
String peerId = null;
if (peerIdBytes.length > 64)
peerId = Hex.toHexString(peerIdBytes, 1, 64);
else
peerId = Hex.toHexString(peerIdBytes);
return Hex.decode(peerId);
}
}

View File

@ -122,7 +122,5 @@ public class BlockChainTable extends JFrame {
BlockChainTable mainFrame = new BlockChainTable();
mainFrame.setVisible(true);
mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}

View File

@ -1,5 +1,9 @@
package org.ethereum.gui;
import org.ethereum.core.Address;
import org.ethereum.util.Utils;
import org.spongycastle.util.encoders.Hex;
import javax.swing.*;
import javax.swing.border.Border;
import javax.swing.border.CompoundBorder;
@ -7,6 +11,7 @@ import javax.swing.border.EmptyBorder;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.math.BigInteger;
import java.net.URL;
/**
@ -16,11 +21,10 @@ import java.net.URL;
*/
public class WalletAddressPanel extends JPanel{
public WalletAddressPanel() {
public WalletAddressPanel(Address address, BigInteger balance) {
this.setBackground(Color.WHITE);
double width = this.getSize().getWidth();
this.setPreferredSize(new Dimension(500, 50));
this.setPreferredSize(new Dimension(500, 45));
JTextField addressField = new JTextField();
Border line = BorderFactory.createLineBorder(Color.LIGHT_GRAY);
@ -29,8 +33,10 @@ public class WalletAddressPanel extends JPanel{
addressField.setBorder(border);
addressField.setEnabled(true);
addressField.setEditable(false);
addressField.setText("5a554ee950faddf206972771bebd3dc0f13f1f4d");
addressField.setText(Hex.toHexString(address.getPubKey()).toUpperCase());
addressField.setForeground(new Color(143, 170, 220));
addressField.setFont(new Font("Monospaced", 0, 12));
addressField.setPreferredSize(new Dimension(300, 35));
addressField.setBackground(Color.WHITE);
this.add(addressField);
@ -38,9 +44,12 @@ public class WalletAddressPanel extends JPanel{
amount.setBorder(border);
amount.setEnabled(true);
amount.setEditable(false);
amount.setText("234 * 10^9");
amount.setText(Utils.getValueShortString(balance));
amount.setForeground(new Color(143, 170, 220));
amount.setBackground(Color.WHITE);
amount.setPreferredSize(new Dimension(100, 35));
amount.setFont(new Font("Monospaced", 0, 13));
amount.setHorizontalAlignment(SwingConstants.RIGHT);
this.add(amount);
URL payoutIconURL = ClassLoader.getSystemResource("buttons/wallet-pay.png");

View File

@ -1,5 +1,7 @@
package org.ethereum.gui;
import org.ethereum.util.Utils;
import javax.swing.*;
import javax.swing.border.Border;
import javax.swing.border.CompoundBorder;
@ -9,6 +11,7 @@ import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.math.BigInteger;
import java.net.URL;
/**
@ -28,15 +31,18 @@ public class WalletSumPanel extends JPanel{
CompoundBorder border = new CompoundBorder(line, empty);
JLabel addressField = new JLabel();
addressField.setPreferredSize(new Dimension(276, 50));
addressField.setPreferredSize(new Dimension(300, 35));
this.add(addressField);
JTextField amount = new JTextField();
amount.setBorder(border);
amount.setEnabled(true);
amount.setEditable(false);
amount.setText("234 * 10^9");
amount.setText(Utils.getValueShortString(new BigInteger("9288972348723947238947")));
amount.setPreferredSize(new Dimension(100, 35));
amount.setForeground(new Color(143, 170, 220));
amount.setHorizontalAlignment(SwingConstants.RIGHT);
amount.setFont(new Font("Monospaced", 0, 13));
amount.setBackground(Color.WHITE);
this.add(amount);

View File

@ -1,9 +1,10 @@
package org.ethereum.gui;
import org.ethereum.core.Address;
import org.ethereum.core.Wallet;
import org.ethereum.manager.MainData;
import javax.swing.*;
import javax.swing.border.Border;
import javax.swing.border.CompoundBorder;
import javax.swing.border.EmptyBorder;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
@ -14,37 +15,53 @@ import java.net.URL;
* User: Roman Mandeleil
* Created on: 17/05/14 12:00
*/
public class WalletWindow extends JFrame {
public class WalletWindow extends JFrame implements Wallet.WalletListener{
WalletWindow walletWindow;
public WalletWindow() {
walletWindow = this;
java.net.URL url = ClassLoader.getSystemResource("ethereum-icon.png");
Toolkit kit = Toolkit.getDefaultToolkit();
Image img = kit.createImage(url);
this.setIconImage(img);
setTitle("Ethereum Wallet");
setSize(490, 370);
setSize(550, 280);
setLocation(215, 280);
setBackground(Color.WHITE);
setResizable(false);
Container contentPane = this.getContentPane();
contentPane.setBackground(new Color(255, 255, 255));
Wallet wallet = MainData.instance.getWallet();
wallet.addListener(this);
loadWallet();
}
private void loadWallet(){
Container contentPane = this.getContentPane();
contentPane.removeAll();
contentPane.setLayout(new FlowLayout());
contentPane.setBackground(Color.WHITE);
WalletAddressPanel panel1 = new WalletAddressPanel();
WalletAddressPanel panel2 = new WalletAddressPanel();
WalletAddressPanel panel3 = new WalletAddressPanel();
WalletAddressPanel panel4 = new WalletAddressPanel();
WalletSumPanel panel5 = new WalletSumPanel();
Wallet wallet = MainData.instance.getWallet();
contentPane.add(panel1);
contentPane.add(panel2);
contentPane.add(panel3);
contentPane.add(panel4);
contentPane.add(panel5);
for (Address address : wallet.getAddressSet()){
WalletAddressPanel rowPanel =
new WalletAddressPanel(address, wallet.getBalance(address));
contentPane.add(rowPanel);
}
WalletSumPanel sumPanel = new WalletSumPanel();
contentPane.add(sumPanel);
// Todo: move this to some add button method
URL addAddressIconURL = ClassLoader.getSystemResource("buttons/add-address.png");
ImageIcon addAddressIcon = new ImageIcon(addAddressIconURL);
JLabel addAddressLabel = new JLabel(addAddressIcon);
@ -53,11 +70,35 @@ public class WalletWindow extends JFrame {
addAddressLabel.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
System.out.println("boom");
Wallet wallet = MainData.instance.getWallet();
if (wallet.getAddressSet().size() >=5){
JOptionPane.showMessageDialog(walletWindow,
"Hey do you really need more than 5 address for a demo wallet");
return;
}
wallet.addNewKey();
Dimension dimension = walletWindow.getSize();
int height = dimension.height;
int width = dimension.width;
Dimension newDimension = new Dimension(width, (height + 45));
walletWindow.setSize(newDimension);
}
});
contentPane.add(addAddressLabel);
contentPane.revalidate();
contentPane.repaint();
}
@Override
public void valueChanged() {
loadWallet();
}
}

View File

@ -4,6 +4,7 @@ import com.maxmind.geoip.Location;
import org.ethereum.core.Block;
import org.ethereum.core.Transaction;
import org.ethereum.core.Wallet;
import org.ethereum.geodb.IpGeoDB;
import org.ethereum.net.client.PeerData;
import org.ethereum.net.message.StaticMessages;
@ -23,9 +24,14 @@ public class MainData {
private Set<PeerData> peers = Collections.synchronizedSet(new HashSet<PeerData>());
private List<Block> blockChainDB = new ArrayList<Block>();
private Wallet wallet = new Wallet();
public static MainData instance = new MainData();
public MainData() {
wallet.addNewKey();
wallet.addNewKey();
}
public void addPeers(List<PeerData> newPeers){
@ -85,5 +91,11 @@ public class MainData {
return blockChainDB;
}
public Wallet getWallet() {
return wallet;
}
public void addTransactions(List<Transaction> transactions) {}
}

View File

@ -64,6 +64,7 @@ public class EthereumProtocolHandler extends ChannelInboundHandlerAdapter {
buffer.writeBytes(MAGIC_PREFIX);
buffer.writeBytes(HELLO_MESSAGE_LEN);
buffer.writeBytes(HELLO_MESSAGE);
System.out.println("Send: " + StaticMessages.HELLO_MESSAGE.toString());
ctx.writeAndFlush(buffer);
// sample for pinging in background
@ -102,6 +103,9 @@ public class EthereumProtocolHandler extends ChannelInboundHandlerAdapter {
}
}, 2000, 30000);
// todo: stop that one
// todo: and schedule one slower
// todo: once the chain is downloaded
timer.schedule(new TimerTask() {
public void run() {

View File

@ -35,6 +35,7 @@ public class HelloMessage extends Message {
this.capabilities = capabilities;
this.peerPort = peerPort;
this.peerId = peerId;
this.parsed = true;
}
@Override

View File

@ -1,5 +1,6 @@
package org.ethereum.net.message;
import org.ethereum.crypto.HashUtil;
import org.ethereum.util.Utils;
import org.spongycastle.util.encoders.Hex;
@ -53,12 +54,8 @@ public class StaticMessages {
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 " +
"17 B6 F1 F1 F1 F1 41 D3 C6 C6 54 B7 AE 88 B2 39 " +
"40 7F F1 F1 F1 F1 19 02 5D 78 57 27 ED 01 7B 6A " +
"DD 21 F1 F1 F1 F1 00 00 01 E3 21 DB C3 18 24 BA ";
byte[] peerIdBytes = Utils.hexStringToByteArr(peerId);
byte[] peerIdBytes = HashUtil.randomPeerId();
HELLO_MESSAGE = new HelloMessage((byte)0x0F, (byte)0x00, "EthereumJ [v0.0.1] pure java [by Roman Mandeleil]",
(byte)0b00000111, (short)30303, peerIdBytes);

View File

@ -2,6 +2,7 @@ package org.ethereum.util;
import java.math.BigInteger;
import java.net.URL;
import java.security.SecureRandom;
import java.util.regex.Pattern;
import javax.swing.ImageIcon;
@ -15,6 +16,8 @@ import org.spongycastle.util.encoders.Hex;
*/
public class Utils {
private static SecureRandom random = new SecureRandom();
public static byte[] hexStringToByteArr(String hexString){
String hexSymbols = "0123456789ABCDEF";
@ -91,4 +94,23 @@ public class Utils {
return size;
}
static BigInteger thousand = new BigInteger("1000");
public static String getValueShortString(BigInteger number){
BigInteger result = number;
int pow = 0;
while (result.compareTo(thousand) == 1){
result = result.divide(thousand);
pow += 3;
}
return result.toString() + " (" + "10^" + pow + ")";
}
public static SecureRandom getRandom(){
return random;
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

After

Width:  |  Height:  |  Size: 3.7 KiB

View File

@ -0,0 +1,21 @@
package org.ethereum.core;
import org.junit.Test;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.TransformerException;
/**
* www.ethereumJ.com
* User: Roman Mandeleil
* Created on: 17/05/14 17:06
*/
public class WalletTest {
@Test
public void SaveTest1() throws TransformerException, ParserConfigurationException {
Wallet wallet = new Wallet();
wallet.save();
}
}

View File

@ -89,5 +89,10 @@ public class CryptoTest {
public void test9(){
// todo: https://tools.ietf.org/html/rfc6979#section-2.2
// todo: https://github.com/bcgit/bc-java/blob/master/core/src/main/java/org/bouncycastle/crypto/signers/ECDSASigner.java
System.out.println(new BigInteger(1, Hex.decode("3913517ebd3c0c65000000")));
System.out.println(Utils.getValueShortString(new BigInteger("69000000000000000000000000")));
}
}

View File

@ -2,6 +2,7 @@ package org.ethereum.net;
import static org.junit.Assert.*;
import java.math.BigInteger;
import java.net.UnknownHostException;
import java.util.List;
@ -517,7 +518,8 @@ public class MessagesTest {
byte[] size = Utils.calcPacketSize( getChainMessage.getPayload());
assertEquals("00000067", Utils.toHexString(size));
}
}
}

View File

@ -0,0 +1,65 @@
package org.ethereum.util;
import junit.framework.Assert;
import org.junit.Test;
import org.spongycastle.util.encoders.Hex;
import java.math.BigInteger;
import static org.junit.Assert.assertEquals;
/**
* www.ethereumJ.com
* User: Roman Mandeleil
* Created on: 17/05/14 15:38
*/
public class UtilsTest {
@Test
public void getValueShortString1(){
String expected = "123 (10^24)";
String result = Utils.getValueShortString(new BigInteger("123456789123445654363653463"));
assertEquals(expected, result);
}
@Test
public void getValueShortString2(){
String expected = "123 (10^3)";
String result = Utils.getValueShortString(new BigInteger("123456"));
assertEquals(expected, result);
}
@Test
public void getValueShortString3(){
String expected = "1 (10^3)";
String result = Utils.getValueShortString(new BigInteger("1234"));
assertEquals(expected, result);
}
@Test
public void getValueShortString4(){
String expected = "123 (10^0)";
String result = Utils.getValueShortString(new BigInteger("123"));
assertEquals(expected, result);
}
@Test
public void getValueShortString5(){
byte[] decimal = Hex.decode("3913517ebd3c0c65000000");
String expected = "69 (10^24)";
String result = Utils.getValueShortString(new BigInteger(decimal));
assertEquals(expected, result);
}
}