Updating the wallet to work with:

1) AddressState
2) The PayOutDialog works for real now
This commit is contained in:
romanman 2014-05-21 14:19:49 +03:00
parent 6dabaad525
commit a16fa04e59
13 changed files with 182 additions and 78 deletions

View File

@ -1,5 +1,7 @@
package org.ethereum.core;
import org.ethereum.crypto.ECKey;
import org.ethereum.wallet.AddressState;
import org.spongycastle.util.encoders.Hex;
import org.w3c.dom.*;
import org.xml.sax.SAXException;
@ -16,9 +18,9 @@ import java.io.File;
import java.io.IOException;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Set;
/**
* www.ethereumJ.com
@ -27,20 +29,31 @@ import java.util.Set;
*/
public class Wallet {
private HashMap<Address, BigInteger> rows = new HashMap<>();
private List<WalletListener> listeners = new ArrayList();
// todo: a) the values I need to keep for address state is balance & nonce & ECKey
// todo: b) keep it to be easy accessed by the toAddress()
// private HashMap<Address, BigInteger> rows = new HashMap<>();
// <address, info> table for a wallet
private HashMap<String, AddressState> rows = new HashMap<String, AddressState>();
private long high;
private List<WalletListener> listeners = new ArrayList();
public void addNewKey(){
Address address = new Address();
rows.put(address, BigInteger.ZERO);
AddressState addressState = new AddressState();
String address = Hex.toHexString(addressState.getEcKey().getAddress());
rows.put(address, addressState);
for (WalletListener listener : listeners) listener.valueChanged();
}
public void importKey(byte[] privKey){
Address address = new Address(privKey);
rows.put(address, BigInteger.ZERO);
AddressState addressState = new AddressState(ECKey.fromPrivate(privKey));
String address = Hex.toHexString(addressState.getEcKey().getAddress());
rows.put(address, addressState);
notifyListeners();
}
@ -48,25 +61,28 @@ public class Wallet {
this.listeners.add(walletListener);
}
public Set<Address> getAddressSet(){
return rows.keySet();
public Collection<AddressState> getAddressStateCollection(){
return rows.values();
}
public AddressState getAddressState(byte[] addressBytes){
public BigInteger setBalance(Address address, BigInteger balance){
return rows.put(address, balance);
}
public BigInteger getBalance(Address address){
String address = Hex.toHexString(addressBytes);
return rows.get(address);
}
public BigInteger getBalance(byte[] addressBytes){
String address = Hex.toHexString(addressBytes);
return rows.get(address).getBalance();
}
public BigInteger totalBalance(){
BigInteger sum = BigInteger.ZERO;
for (BigInteger value : rows.values()){
sum = sum.add(value);
for (AddressState addressState : rows.values()){
sum = sum.add(addressState.getBalance());
}
return sum;
}
@ -81,15 +97,13 @@ public class Wallet {
for (Transaction tx : transactions){
byte[] pubKey = tx.getReceiveAddress();
Address receiveAddress = new Address(null, pubKey);
BigInteger balance = getBalance(receiveAddress);
// todo: validate the transaction and decrypt the sender
if (balance != null){
// todo: validate the transaction and decrypt the sender
setBalance(receiveAddress, balance.add(new BigInteger(1, tx.getValue())));
byte[] address = tx.getReceiveAddress();
AddressState addressState = rows.get(Hex.toHexString(address));
if (addressState != null){
addressState.addToBalance(new BigInteger(1, tx.getValue()));
walletUpdated = true;
}
}
@ -140,12 +154,13 @@ public class Wallet {
Node privNode = rowNode.getChildNodes().item(1);
Node valueNode = rowNode.getChildNodes().item(2);
byte[] privKey = Hex.decode(privNode.getTextContent());
Address address = new Address(privKey);
BigInteger value = new BigInteger(valueNode.getTextContent());
// todo: complete load func
// byte[] privKey = Hex.decode(privNode.getTextContent());
// Address address = new Address(privKey);
// BigInteger value = new BigInteger(valueNode.getTextContent());
this.importKey(privKey);
this.setBalance(address, value);
// this.importKey(privKey);
// this.setBalance(address, value);
}
@ -189,7 +204,7 @@ public class Wallet {
walletElement.setAttributeNode(high);
int i = 0;
for (Address address : getAddressSet()){
for (AddressState addressState : getAddressStateCollection()){
Element raw = doc.createElement("raw");
Attr id = doc.createAttribute("id");
@ -197,17 +212,17 @@ public class Wallet {
raw.setAttributeNode(id);
Element addressE = doc.createElement("address");
addressE.setTextContent(Hex.toHexString(address.getAddress()));
addressE.setTextContent(Hex.toHexString(addressState.getEcKey().getAddress()));
Attr nonce = doc.createAttribute("nonce");
nonce.setValue("0");
addressE.setAttributeNode(nonce);
Element privKey = doc.createElement("privkey");
privKey.setTextContent(Hex.toHexString(address.getPrivKey()));
privKey.setTextContent(Hex.toHexString(addressState.getEcKey().getPrivKeyBytes()));
Element value = doc.createElement("value");
value.setTextContent(getBalance(address).toString());
value.setTextContent(addressState.getBalance().toString());
raw.appendChild(addressE);
raw.appendChild(privKey);

View File

@ -71,14 +71,13 @@ public class ConnectionConsoleWindow extends JFrame implements PeerListener{
// new ClientPeer(thisConsole).connect("54.201.28.117", 30303); // peer discovery
// new ClientPeer(thisConsole).connect("82.217.72.169", 30303); // Nick
// new ClientPeer(thisConsole).connect("82.217.72.169", 30303); // Nick
// new ClientPeer(thisConsole).connect("54.204.10.41", 30303);
// new ClientPeer(thisConsole).connect("54.211.14.10", 30303);
// new ClientPeer(thisConsole).connect("54.204.10.41", 30303); // CPP: ZeroGox Poc5
new ClientPeer(thisConsole).connect("54.211.14.10", 30303); // CPP: ver16
new ClientPeer(thisConsole).connect("54.211.14.10", 40404); // CPP: ver16
// new ClientPeer(thisConsole).connect("192.168.1.102", 30303);
}

View File

@ -5,6 +5,7 @@ import org.ethereum.core.Transaction;
import org.ethereum.crypto.HashUtil;
import org.ethereum.manager.MainData;
import org.ethereum.net.client.ClientPeer;
import org.ethereum.wallet.AddressState;
import org.spongycastle.util.BigIntegers;
import org.spongycastle.util.encoders.Hex;
@ -22,17 +23,21 @@ import javax.swing.*;
*/
class PayOutDialog extends JDialog {
public PayOutDialog(Frame parent, BigInteger maxAmount) {
AddressState addressState = null;
public PayOutDialog(Frame parent, final AddressState addressState) {
super(parent, "Payout details: ", false);
this.addressState = addressState;
JLabel receiver = new JLabel("receiver: ");
JTextField receiverInput = new JTextField(18);
final JTextField receiverInput = new JTextField(18);
receiverInput.setHorizontalAlignment(SwingConstants.RIGHT);
JLabel amount = new JLabel("amount: ");
JTextField amountInput = new JTextField(18);
final JLabel amount = new JLabel("amount: ");
final JTextField amountInput = new JTextField(18);
amountInput.setHorizontalAlignment(SwingConstants.RIGHT);
amountInput.setText(maxAmount.toString());
amountInput.setText(addressState.getBalance().toString());
this.getContentPane().setBackground(Color.WHITE);
this.getContentPane().setLayout(new GridLayout(0, 1, 0, 0));
@ -61,18 +66,18 @@ class PayOutDialog extends JDialog {
// Client
ClientPeer peer = MainData.instance.getActivePeer();
BigInteger value = new BigInteger("1000000000000000000000000");
byte[] privKey = HashUtil.sha3("cat".getBytes());
Address receiveAddress = new Address(privKey);
BigInteger value = new BigInteger(amountInput.getText());
byte[] address = Hex.decode(receiverInput.getText());
byte[] senderPrivKey = HashUtil.sha3("cow".getBytes());
byte[] nonce = addressState.getNonce() == BigInteger.ZERO ?
null : addressState.getNonce().toByteArray();
byte[] gasPrice= Hex.decode("09184e72a000");
byte[] gas = Hex.decode("4255");
Transaction tx = new Transaction(null, gasPrice, gas,
receiveAddress.getAddress(), BigIntegers.asUnsignedByteArray(value), null);
Transaction tx = new Transaction(nonce, gasPrice, gas,
address, BigIntegers.asUnsignedByteArray(value), null);
try {
tx.sign(senderPrivKey);
@ -83,6 +88,7 @@ class PayOutDialog extends JDialog {
}
peer.sendTransaction(tx);
addressState.incrementTheNonce();
}
}
);

View File

@ -2,6 +2,7 @@ package org.ethereum.gui;
import org.ethereum.core.Address;
import org.ethereum.util.Utils;
import org.ethereum.wallet.AddressState;
import org.spongycastle.util.encoders.Hex;
import javax.swing.*;
@ -21,7 +22,7 @@ import java.net.URL;
*/
public class WalletAddressPanel extends JPanel{
public WalletAddressPanel(Address address, final BigInteger balance) {
public WalletAddressPanel(final AddressState addressState) {
final WalletAddressPanel walletAddressPanel = this;
@ -35,7 +36,7 @@ public class WalletAddressPanel extends JPanel{
addressField.setBorder(border);
addressField.setEnabled(true);
addressField.setEditable(false);
addressField.setText(Hex.toHexString(address.getAddress()).toUpperCase());
addressField.setText(Hex.toHexString(addressState.getEcKey().getAddress()).toUpperCase());
addressField.setForeground(new Color(143, 170, 220));
addressField.setFont(new Font("Monospaced", 0, 12));
addressField.setPreferredSize(new Dimension(300, 35));
@ -46,7 +47,7 @@ public class WalletAddressPanel extends JPanel{
amount.setBorder(border);
amount.setEnabled(true);
amount.setEditable(false);
amount.setText(Utils.getValueShortString(balance));
amount.setText(Utils.getValueShortString(addressState.getBalance()));
amount.setForeground(new Color(143, 170, 220));
amount.setBackground(Color.WHITE);
amount.setPreferredSize(new Dimension(100, 35));
@ -65,7 +66,7 @@ public class WalletAddressPanel extends JPanel{
PayOutDialog payOutDialog =
new PayOutDialog((Frame)SwingUtilities.getAncestorOfClass(Frame.class,
walletAddressPanel), balance);
walletAddressPanel), addressState);
}
});

View File

@ -3,6 +3,7 @@ package org.ethereum.gui;
import org.ethereum.core.Address;
import org.ethereum.core.Wallet;
import org.ethereum.manager.MainData;
import org.ethereum.wallet.AddressState;
import javax.swing.*;
import java.awt.*;
@ -49,10 +50,10 @@ public class WalletWindow extends JFrame implements Wallet.WalletListener{
Wallet wallet = MainData.instance.getWallet();
for (Address address : wallet.getAddressSet()){
for (AddressState addressState : wallet.getAddressStateCollection()){
WalletAddressPanel rowPanel =
new WalletAddressPanel(address, wallet.getBalance(address));
new WalletAddressPanel(addressState);
contentPane.add(rowPanel);
}
@ -71,7 +72,7 @@ public class WalletWindow extends JFrame implements Wallet.WalletListener{
public void mouseClicked(MouseEvent e) {
Wallet wallet = MainData.instance.getWallet();
if (wallet.getAddressSet().size() >=5){
if (wallet.getAddressStateCollection().size() >=5){
JOptionPane.showMessageDialog(walletWindow,
"Hey do you really need more than 5 address for a demo wallet");
return;

View File

@ -81,7 +81,7 @@ public class MainData {
if (!hashLast.equals(blockParentHash)) return;
}
for (int i = blocks.size() - 1; i > 0 ; --i){
for (int i = blocks.size() - 1; i >= 0 ; --i){
Block block = blocks.get(i);
blockChainDB.add(block);
wallet.processBlock(block);

View File

@ -161,22 +161,22 @@ public class EthereumProtocolHandler extends ChannelInboundHandlerAdapter {
System.out.println("[Recv: GETPEERS]" );
if (peerListener != null) peerListener.console("[Recv: GETPEERS]");
String answer = "2240089100000134F9013111F84A8456084B1482765FB84072FD5DBC7F458FB0A52354E25234CEA90A51EA09858A21406056D9B9E0826BB153527E4C4CBEC53B46B0245E6E8503EEABDBF0F1789D7C5C78BBF2B1FDD9090CF84A8455417E2D82765FB840CE73F1F1F1F16C1B3FDA7B18EF7BA3CE17B6F1F1F1F141D3C6C654B7AE88B239407FF1F1F1F119025D785727ED017B6ADD21F1F1F1F1000001E321DBC31824BAF84A8436C91C7582765FB840D592C570B5082D357C30E61E3D8F26317BFD7A3A2A00A36CFB7254FEE80830F26DDFBD6A99712552F3D77314DB4AB58B9989F25699C4997A0F62489D4B86CB4DF84A8436CC0A2982765FB840E34C6E3EAC28CFD3DC930A5AEFD9552FEBCD72C33DFC74D8E4C7CF8A7BA71AE53316ADDBD241EB051ED0871C2B62825E66A45DC6A0E752A7F1C22ABEF9ABDE32";
byte[] answerBytes = Hex.decode(answer);
// String answer = "2240089100000134F9013111F84A8456084B1482765FB84072FD5DBC7F458FB0A52354E25234CEA90A51EA09858A21406056D9B9E0826BB153527E4C4CBEC53B46B0245E6E8503EEABDBF0F1789D7C5C78BBF2B1FDD9090CF84A8455417E2D82765FB840CE73F1F1F1F16C1B3FDA7B18EF7BA3CE17B6F1F1F1F141D3C6C654B7AE88B239407FF1F1F1F119025D785727ED017B6ADD21F1F1F1F1000001E321DBC31824BAF84A8436C91C7582765FB840D592C570B5082D357C30E61E3D8F26317BFD7A3A2A00A36CFB7254FEE80830F26DDFBD6A99712552F3D77314DB4AB58B9989F25699C4997A0F62489D4B86CB4DF84A8436CC0A2982765FB840E34C6E3EAC28CFD3DC930A5AEFD9552FEBCD72C33DFC74D8E4C7CF8A7BA71AE53316ADDBD241EB051ED0871C2B62825E66A45DC6A0E752A7F1C22ABEF9ABDE32";
// byte[] answerBytes = Hex.decode(answer);
ByteBuf buffer = ctx.alloc().buffer(answerBytes.length);
buffer.writeBytes(answerBytes);
ctx.writeAndFlush(buffer);
// ByteBuf buffer = ctx.alloc().buffer(answerBytes.length);
// buffer.writeBytes(answerBytes);
// ctx.writeAndFlush(buffer);
// send getpeers
answer = "22 40 08 91 00 00 00 02 C1 10 ";
answerBytes = Hex.decode(answer);
buffer = ctx.alloc().buffer(answerBytes.length);
// answer = "22 40 08 91 00 00 00 02 C1 10 ";
// answerBytes = Hex.decode(answer);
// buffer = ctx.alloc().buffer(answerBytes.length);
answerBytes = Utils.hexStringToByteArr(answer);
buffer = ctx.alloc().buffer(answerBytes.length);
buffer.writeBytes(answerBytes);
ctx.writeAndFlush(buffer);
// answerBytes = Utils.hexStringToByteArr(answer);
// buffer = ctx.alloc().buffer(answerBytes.length);
// buffer.writeBytes(answerBytes);
// ctx.writeAndFlush(buffer);
}
// got PEERS
if (Command.fromInt(command) == PEERS) {

View File

@ -106,18 +106,16 @@ public class Utils {
return size;
}
static BigInteger thousand = new BigInteger("1000");
static BigInteger _1000_ = new BigInteger("1000");
public static String getValueShortString(BigInteger number){
BigInteger result = number;
int pow = 0;
while (result.compareTo(thousand) == 1){
while (result.compareTo(_1000_) == 1 || result.compareTo(_1000_) == 0){
result = result.divide(thousand);
result = result.divide(_1000_);
pow += 3;
}
return result.toString() + " (" + "10^" + pow + ")";
}

View File

@ -0,0 +1,61 @@
package org.ethereum.wallet;
import org.ethereum.crypto.ECKey;
import org.ethereum.util.Utils;
import java.math.BigInteger;
/**
* www.ethereumJ.com
* User: Roman Mandeleil
* Created on: 21/05/2014 10:43
*/
public class AddressState {
private ECKey ecKey;
private BigInteger nonce;
private BigInteger balance;
public AddressState() {
ecKey = new ECKey(Utils.getRandom());
nonce = BigInteger.ZERO;
balance = BigInteger.ZERO;
}
public AddressState(ECKey ecKey) {
this();
this.ecKey = ecKey;
}
public AddressState(ECKey ecKey, BigInteger nonce, BigInteger balance) {
this.ecKey = ecKey;
this.nonce = nonce;
this.balance = balance;
}
public ECKey getEcKey() {
return ecKey;
}
public BigInteger getNonce() {
return nonce;
}
public void incrementTheNonce(){
nonce = nonce.add(BigInteger.ONE);
}
public BigInteger getBalance() {
return balance;
}
public void addToBalance(BigInteger value){
balance = balance.add(value);
}
}

View File

@ -0,0 +1,16 @@
#***
# Starting to gather some properties the system going to support
#***
# if the system will work as a server also
# accept for incoming connections [true/false]
server.acceptConnections = false
# connection timeout is going to be
# used also on the try to connect
# and read new wire msg if the timeout
# fires the system will be looking for
# another peer. [seconds]
connection.timeout = 10

View File

@ -44,8 +44,8 @@ public class TransactionTest {
@Test /* achieve public key of the sender */
public void test2() throws Exception {
// cat --> 79B08AD8787060333663D19704909EE7B1903E58
// cow --> CD2A3D9F938E13CD947EC05ABC7FE734DF8DD826
// cat --> 79b08ad8787060333663d19704909ee7b1903e58
// cow --> cd2a3d9f938e13cd947ec05abc7fe734df8dd826
BigInteger value = new BigInteger("1000000000000000000000000");

View File

@ -1,6 +1,8 @@
package org.ethereum.core;
import org.ethereum.crypto.ECKey;
import org.ethereum.crypto.HashUtil;
import org.ethereum.wallet.AddressState;
import org.junit.Test;
import org.xml.sax.SAXException;
@ -20,14 +22,18 @@ public class WalletTest {
public void SaveTest1() throws TransformerException, ParserConfigurationException {
Wallet wallet = new Wallet();
wallet.importKey(HashUtil.sha3("cow".getBytes()));
wallet.importKey(HashUtil.sha3("cat".getBytes()));
ECKey cowKey = ECKey.fromPrivate( HashUtil.sha3("cow".getBytes()) );
ECKey catKey = ECKey.fromPrivate( HashUtil.sha3("cat".getBytes()) );
Address addr1 = (Address) wallet.getAddressSet().toArray()[0];
Address addr2 = (Address) wallet.getAddressSet().toArray()[1];
wallet.importKey(cowKey.getPrivKeyBytes());
wallet.importKey(catKey.getPrivKeyBytes());
wallet.setBalance(addr1, new BigInteger("234234"));
wallet.setBalance(addr2, new BigInteger("84758"));
AddressState cowAddressState = (AddressState) wallet.getAddressState(cowKey.getAddress());
AddressState catAddressState = (AddressState) wallet.getAddressState(catKey.getAddress());
cowAddressState.addToBalance(new BigInteger("234234"));
catAddressState.addToBalance(new BigInteger("84758"));
wallet.setHigh(4354);

View File

@ -75,6 +75,7 @@ public class ECKeyTest {
assertArrayEquals(key.getPubKey(), pubKey);
}
@Test
public void testPublicKeyFromPrivate() {
byte[] pubFromPriv = ECKey.publicKeyFromPrivate(privateKey, false);