Merge pull request #21 from nicksavers/master

Impl faster ADD
This commit is contained in:
romanman 2014-06-05 06:34:19 +03:00
commit 734d25bdc0
24 changed files with 292 additions and 231 deletions

View File

@ -19,13 +19,20 @@ public class SystemProperties {
private static Logger logger = LoggerFactory.getLogger(SystemProperties.class); private static Logger logger = LoggerFactory.getLogger(SystemProperties.class);
private static int DEFAULT_TX_APPROVE_TIMEOUT = 10;
private static String DEFAULT_DISCOVERY_PEER = "54.201.28.117";
private static int DEFAULT_DISCOVERY_PORT = 30303;
private static String DEFAULT_ACTIVE_PEER_IP = "54.201.28.117";
private static int DEFAULT_ACTIVE_PORT = 30303;
private static String DEFAULT_SAMPLES_DIR = "samples";
public static SystemProperties CONFIG = new SystemProperties(); public static SystemProperties CONFIG = new SystemProperties();
private Properties prop = new Properties(); private Properties prop = new Properties();
private InputStream input = null; private InputStream input = null;
public SystemProperties() { public SystemProperties() {
try {
try {
File file = null; File file = null;
String dir = System.getProperty("user.dir"); String dir = System.getProperty("user.dir");
String fileName = dir + "/config/system.properties"; String fileName = dir + "/config/system.properties";
@ -41,7 +48,6 @@ public class SystemProperties {
return; return;
} }
} }
//load a properties file from class path, inside static method //load a properties file from class path, inside static method
prop.load(input); prop.load(input);
@ -77,18 +83,17 @@ public class SystemProperties {
public int transactionApproveTimeout(){ public int transactionApproveTimeout(){
if (prop.isEmpty()) if (prop.isEmpty())
return 10; return DEFAULT_TX_APPROVE_TIMEOUT;
return Integer.parseInt(prop.getProperty("transaction.approve.timeout")); return Integer.parseInt(prop.getProperty("transaction.approve.timeout"));
} }
public String peerDiscoveryIP(){ public String peerDiscoveryIP(){
if(prop.isEmpty()) return "54.201.28.117"; if(prop.isEmpty()) return DEFAULT_DISCOVERY_PEER;
return prop.getProperty("peer.discovery.ip"); return prop.getProperty("peer.discovery.ip");
} }
public int peerDiscoveryPort(){ public int peerDiscoveryPort(){
if(prop.isEmpty()) return 30303; if(prop.isEmpty()) return DEFAULT_DISCOVERY_PORT;
return Integer.parseInt(prop.getProperty("peer.discovery.port")); return Integer.parseInt(prop.getProperty("peer.discovery.port"));
} }
@ -98,21 +103,21 @@ public class SystemProperties {
} }
public String activePeerIP(){ public String activePeerIP(){
if(prop.isEmpty()) return "54.201.28.117"; if(prop.isEmpty()) return DEFAULT_ACTIVE_PEER_IP;
return prop.getProperty("peer.active.ip"); return prop.getProperty("peer.active.ip");
} }
public int activePeerPort(){ public int activePeerPort(){
if(prop.isEmpty()) return 30303; if(prop.isEmpty()) return DEFAULT_ACTIVE_PORT;
return Integer.parseInt(prop.getProperty("peer.active.port")); return Integer.parseInt(prop.getProperty("peer.active.port"));
} }
public String samplesDir(){ public String samplesDir(){
if(prop.isEmpty()) return "samples"; if(prop.isEmpty()) return DEFAULT_SAMPLES_DIR;
return prop.getProperty("samples.dir"); return prop.getProperty("samples.dir");
} }
public String toString() { public void print() {
Enumeration<?> e = prop.propertyNames(); Enumeration<?> e = prop.propertyNames();
while (e.hasMoreElements()) { while (e.hasMoreElements()) {
String key = (String) e.nextElement(); String key = (String) e.nextElement();
@ -120,11 +125,10 @@ public class SystemProperties {
if (!key.equals("null")) if (!key.equals("null"))
logger.info("Key: " + key + ", Value: " + value); logger.info("Key: " + key + ", Value: " + value);
} }
return "";
} }
public static void main(String args[]){ public static void main(String args[]){
SystemProperties systemProperties = new SystemProperties(); SystemProperties systemProperties = new SystemProperties();
logger.info(systemProperties.toString()); systemProperties.print();
} }
} }

View File

@ -27,7 +27,7 @@ public class AccountState {
* *
* Since I typically wish to refer not to the tries root hash * Since I typically wish to refer not to the tries root hash
* but to the underlying set of key/value pairs stored within, * but to the underlying set of key/value pairs stored within,
* I define a convenient equi valence TRIE (σ[a] s ) σ[a] s . * I define a convenient equivalence TRIE (σ[a] s ) σ[a] s .
* It shall be understood that σ[a] s is not a physical member * It shall be understood that σ[a] s is not a physical member
* of the account and does not contribute to its later serialisation */ * of the account and does not contribute to its later serialisation */
private byte[] stateRoot = new byte[0]; private byte[] stateRoot = new byte[0];

View File

@ -1,7 +1,6 @@
package org.ethereum.core; package org.ethereum.core;
import java.io.IOException; import java.io.IOException;
import java.math.BigInteger;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
@ -20,31 +19,22 @@ import org.spongycastle.util.encoders.Hex;
public class Blockchain extends ArrayList<Block> { public class Blockchain extends ArrayList<Block> {
private static final long serialVersionUID = -143590724563460486L;
private static Logger logger = LoggerFactory.getLogger(Blockchain.class); private static Logger logger = LoggerFactory.getLogger(Blockchain.class);
private Database db; private Database db;
private Wallet wallet; private Wallet wallet;
private long gasPrice = 1000; private long gasPrice = 1000;
private Block lastBlock = new Genesis(); private Block lastBlock;
private Map<BigInteger, PendingTransaction> pendingTransactions = private Map<String, PendingTransaction> pendingTransactions =
Collections.synchronizedMap(new HashMap<BigInteger, PendingTransaction>()); Collections.synchronizedMap(new HashMap<String, PendingTransaction>());
public Blockchain(Wallet wallet) { public Blockchain(Wallet wallet) {
this.db = Config.CHAIN_DB; this.db = Config.CHAIN_DB;
this.wallet = wallet; this.wallet = wallet;
this.loadChain();
// Redesign fetch all to get the chain ordered
byte[] payload = db.get(Genesis.PARENT_HASH);
while (payload != null) {
Block block = new Block(payload);
this.add(block);
lastBlock = block;
wallet.processBlock(block);
payload = db.get(block.getHash());
}
} }
public Block getLastBlock() { public Block getLastBlock() {
@ -55,59 +45,65 @@ public class Blockchain extends ArrayList<Block> {
// TODO: redesign this part when the state part and the genesis block is ready // TODO: redesign this part when the state part and the genesis block is ready
if (blocks.isEmpty()) return; if (blocks.isEmpty())
return;
Block firstBlockToAdd = blocks.get(blocks.size() - 1); Block firstBlockToAdd = blocks.get(blocks.size() - 1);
// if it is the first block to add // if it is the first block to add
// check that the parent is the genesis // check that the parent is the genesis
if (this.isEmpty() && if (this.isEmpty()
!Arrays.equals(StaticMessages.GENESIS_HASH, firstBlockToAdd.getParentHash())){ && !Arrays.equals(StaticMessages.GENESIS_HASH,
return; firstBlockToAdd.getParentHash())) {
} return;
}
// if there is some blocks already keep chain continuity // if there is some blocks already keep chain continuity
if (!this.isEmpty() ){ if (!this.isEmpty()) {
Block lastBlock = this.get(this.size() - 1); Block lastBlock = this.get(this.size() - 1);
String hashLast = Hex.toHexString(lastBlock.getHash()); String hashLast = Hex.toHexString(lastBlock.getHash());
String blockParentHash = Hex.toHexString(firstBlockToAdd.getParentHash()); String blockParentHash = Hex.toHexString(firstBlockToAdd.getParentHash());
if (!hashLast.equals(blockParentHash)) return; 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); Block block = blocks.get(i);
this.add(block); this.addBlock(block);
if(block.getNumber() > lastBlock.getNumber()) lastBlock = block;
db.put(block.getParentHash(), block.getEncoded()); db.put(block.getParentHash(), block.getEncoded());
if (logger.isDebugEnabled()) if (logger.isDebugEnabled())
logger.debug("block added to the chain with hash: {}", Hex.toHexString(block.getHash())); logger.debug("block added to the chain with hash: {}", Hex.toHexString(block.getHash()));
this.gasPrice = block.getMinGasPrice();
wallet.processBlock(block);
} }
// Remove all pending transactions as they already approved by the net // Remove all pending transactions as they already approved by the net
for (Block block : blocks){ for (Block block : blocks) {
for (Transaction tx : block.getTransactionsList()){ for (Transaction tx : block.getTransactionsList()) {
if (logger.isDebugEnabled()) if (logger.isDebugEnabled())
logger.debug("pending cleanup: tx.hash: [{}]", Hex.toHexString( tx.getHash())); logger.debug("pending cleanup: tx.hash: [{}]", Hex.toHexString( tx.getHash()));
removePendingTransaction(tx); removePendingTransaction(tx);
} }
} }
logger.info("*** Block chain size: [ {} ]", this.size()); logger.info("*** Block chain size: [ {} ]", this.size());
} }
/* private void addBlock(Block block) {
* 1) the dialog put a pending transaction on the list this.wallet.processBlock(block);
* 2) the dialog send the transaction to a net this.gasPrice = block.getMinGasPrice();
* 3) wherever the transaction got in from the wire it will change to approve state if(lastBlock == null || block.getNumber() > lastBlock.getNumber())
* 4) only after the approve a) Wallet state changes this.lastBlock = block;
* 5) After the block is received with that tx the pending been clean up this.add(block);
*/ }
public PendingTransaction addPendingTransaction(Transaction transaction) {
BigInteger hash = new BigInteger(transaction.getHash()); public long getGasPrice() {
logger.info("pending transaction placed hash: {} ", hash.toString(16) ); return gasPrice;
}
/***********************************************************************
* 1) the dialog put a pending transaction on the list
* 2) the dialog send the transaction to a net
* 3) wherever the transaction got in from the wire it will change to approve state
* 4) only after the approve a) Wallet state changes
* 5) After the block is received with that tx the pending been clean up
*/
public PendingTransaction addPendingTransaction(Transaction transaction) {
String hash = Hex.toHexString(transaction.getHash());
logger.info("pending transaction placed hash: {} ", hash );
PendingTransaction pendingTransaction = pendingTransactions.get(hash); PendingTransaction pendingTransaction = pendingTransactions.get(hash);
if (pendingTransaction != null) if (pendingTransaction != null)
@ -120,24 +116,44 @@ public class Blockchain extends ArrayList<Block> {
} }
public void removePendingTransaction(Transaction transaction){ public void removePendingTransaction(Transaction transaction){
String hash = Hex.toHexString(transaction.getHash());
BigInteger hash = new BigInteger(transaction.getHash()); logger.info("pending transaction removed with hash: {} ", hash );
logger.info("pending transaction removed with hash: {} ", hash.toString(16) );
pendingTransactions.remove(hash); pendingTransactions.remove(hash);
} }
public long getGasPrice() {
return gasPrice;
}
public byte[] getLatestBlockHash(){ public byte[] getLatestBlockHash(){
if (this.isEmpty())
if (this.isEmpty()) return StaticMessages.GENESIS_HASH;
return StaticMessages.GENESIS_HASH; else
else{ return lastBlock.getHash();
return lastBlock.getHash();
}
} }
public void loadChain() {
DBIterator iterator = db.iterator();
try {
if (!iterator.hasNext()) {
logger.info("DB is empty - adding Genesis");
Block genesis = Genesis.getInstance();
this.addBlock(genesis);
logger.debug("Block: " + genesis.getNumber() + " ---> " + genesis.toFlatString());
db.put(genesis.getParentHash(), genesis.getEncoded());
} else {
logger.debug("Displaying blocks stored in DB sorted on blocknumber");
byte[] parentHash = Genesis.PARENT_HASH; // get Genesis block by parentHash
for (iterator.seekToFirst(); iterator.hasNext(); iterator.next()) {
this.addBlock(new Block(db.get(parentHash)));
if (logger.isDebugEnabled())
logger.debug("Block: " + lastBlock.getNumber() + " ---> " + lastBlock.toFlatString());
parentHash = lastBlock.getHash();
}
}
} finally {
// Make sure you close the iterator to avoid resource leaks.
try {
iterator.close();
} catch (IOException e) {
logger.error(e.getMessage(), e);
}
}
}
} }

View File

@ -30,7 +30,9 @@ public class Genesis extends Block {
public static byte[] EXTRA_DATA = new byte[0]; public static byte[] EXTRA_DATA = new byte[0];
public static byte[] NONCE = HashUtil.sha3(new byte[]{42}); public static byte[] NONCE = HashUtil.sha3(new byte[]{42});
public Genesis() { private static Block instance;
private Genesis() {
super(PARENT_HASH, UNCLES_HASH, COINBASE, TX_TRIE_ROOT, DIFFICULTY, super(PARENT_HASH, UNCLES_HASH, COINBASE, TX_TRIE_ROOT, DIFFICULTY,
NUMBER, MIN_GAS_PRICE, GAS_LIMIT, GAS_USED, TIMESTAMP, NUMBER, MIN_GAS_PRICE, GAS_LIMIT, GAS_USED, TIMESTAMP,
EXTRA_DATA, NONCE, null, null); EXTRA_DATA, NONCE, null, null);
@ -53,9 +55,16 @@ public class Genesis extends Block {
this.updateState(Hex.decode("6c386a4b26f73c802f34673f7248bb118f97424a"), acct.getEncoded()); this.updateState(Hex.decode("6c386a4b26f73c802f34673f7248bb118f97424a"), acct.getEncoded());
// # (R) // # (R)
this.updateState(Hex.decode("cd2a3d9f938e13cd947ec05abc7fe734df8dd826"), acct.getEncoded()); this.updateState(Hex.decode("cd2a3d9f938e13cd947ec05abc7fe734df8dd826"), acct.getEncoded());
System.out.println(Hex.toHexString(this.getStateRoot()));
logger.info("Genesis-hash: " + Hex.toHexString(this.getHash())); logger.info("Genesis-hash: " + Hex.toHexString(this.getHash()));
logger.info("Genesis-stateRoot: " + Hex.toHexString(this.getStateRoot()));
Config.CHAIN_DB.put(getParentHash(), getEncoded()); Config.CHAIN_DB.put(getParentHash(), getEncoded());
} }
public static Block getInstance() {
if (instance == null) {
instance = new Genesis();
}
return instance;
}
} }

View File

@ -160,7 +160,7 @@ public class StateObject {
// Converts an transaction in to a state object // Converts an transaction in to a state object
public static StateObject createContract(Transaction tx, GoState state) { public static StateObject createContract(Transaction tx, GoState state) {
// Create contract if there's no recipient // Create contract if there's no recipient
if (tx.isContract()) { if (tx.isContractCreation()) {
// FIXME // FIXME
byte[] txHash = tx.getHash(); byte[] txHash = tx.getHash();
byte[] contractAddress = copyOfRange(txHash, 12, txHash.length); byte[] contractAddress = copyOfRange(txHash, 12, txHash.length);

View File

@ -164,14 +164,14 @@ public class Transaction {
public byte[] getContractAddress(){ public byte[] getContractAddress(){
if (!isContract()) return null; if (!isContractCreation()) return null;
byte[] encSender = RLP.encodeElement(getSender()); byte[] encSender = RLP.encodeElement(getSender());
byte[] encNonce = RLP.encodeElement(nonce); byte[] encNonce = RLP.encodeElement(nonce);
return HashUtil.sha3omit12(RLP.encodeList(encSender, encNonce)); return HashUtil.sha3omit12(RLP.encodeList(encSender, encNonce));
} }
public boolean isContract() { public boolean isContractCreation() {
return Arrays.equals(this.receiveAddress, ZERO_ADDRESS); return Arrays.equals(this.receiveAddress, ZERO_ADDRESS);
} }

View File

@ -47,7 +47,7 @@ import org.spongycastle.util.encoders.Base64;
import org.spongycastle.util.encoders.Hex; import org.spongycastle.util.encoders.Hex;
public class ECKey implements Serializable { public class ECKey implements Serializable {
private static final Logger log = LoggerFactory.getLogger(ECKey.class); private static final Logger logger = LoggerFactory.getLogger(ECKey.class);
/** The parameters of the secp256k1 curve that Bitcoin uses. */ /** The parameters of the secp256k1 curve that Bitcoin uses. */
public static final ECDomainParameters CURVE; public static final ECDomainParameters CURVE;
@ -448,11 +448,10 @@ public class ECKey implements Serializable {
signer.init(false, params); signer.init(false, params);
try { try {
return signer.verifySignature(data, signature.r, signature.s); return signer.verifySignature(data, signature.r, signature.s);
} catch (NullPointerException e) { } catch (NullPointerException npe) {
// Bouncy Castle contains a bug that can cause NPEs given specially crafted signatures. Those signatures // Bouncy Castle contains a bug that can cause NPEs given specially crafted signatures.
// are inherently invalid/attack sigs so we just fail them here rather than crash the thread. // Those signatures are inherently invalid/attack sigs so we just fail them here rather than crash the thread.
log.error("Caught NPE inside bouncy castle"); logger.error("Caught NPE inside bouncy castle", npe);
e.printStackTrace();
return false; return false;
} }
} }

View File

@ -4,19 +4,13 @@ import static org.iq80.leveldb.impl.Iq80DBFactory.factory;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import org.ethereum.config.SystemProperties; import org.ethereum.config.SystemProperties;
import org.ethereum.core.Block;
import org.ethereum.core.Genesis;
import org.ethereum.net.message.StaticMessages;
import org.iq80.leveldb.DB; import org.iq80.leveldb.DB;
import org.iq80.leveldb.DBIterator; import org.iq80.leveldb.DBIterator;
import org.iq80.leveldb.Options; import org.iq80.leveldb.Options;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.spongycastle.util.encoders.Hex;
/** /**
* Generic interface for Ethereum database * Generic interface for Ethereum database
@ -47,8 +41,6 @@ public class Database {
logger.debug("Initializing new or existing DB: '" + name + "'"); logger.debug("Initializing new or existing DB: '" + name + "'");
options.createIfMissing(true); options.createIfMissing(true);
db = factory.open(new File(name), options); db = factory.open(new File(name), options);
printDB();
// logger.debug("Showing database stats"); // logger.debug("Showing database stats");
// String stats = DATABASE.getProperty("leveldb.stats"); // String stats = DATABASE.getProperty("leveldb.stats");
// logger.debug(stats); // logger.debug(stats);
@ -68,34 +60,6 @@ public class Database {
} }
} }
public void printDB() {
DBIterator iterator = db.iterator();
try {
Map<Long, Block> blocks = new HashMap<Long, Block>();
int count = 0;
if (!iterator.hasNext()) {
logger.info("DB is empty");
} else {
logger.info("Displaying blocks stored in DB sorted on key");
}
for (iterator.seekToFirst(); iterator.hasNext(); iterator.next()) {
byte[] key = iterator.peekNext().getKey();
byte[] value = iterator.peekNext().getValue();
Block block = new Block(value);
blocks.put(new Long(block.getNumber()), block);
logger.info("Block: " + count + " Key: " + Hex.toHexString(key) + " ---> " + block.toFlatString());
count++;
}
} finally {
// Make sure you close the iterator to avoid resource leaks.
try {
iterator.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
/** Insert object(value) (key = sha3(value)) */ /** Insert object(value) (key = sha3(value)) */
public void put(byte[] key, byte[] value) { public void put(byte[] key, byte[] value) {
db.put(key, value); db.put(key, value);

View File

@ -4,6 +4,9 @@ import java.io.File;
import java.net.InetAddress; import java.net.InetAddress;
import java.net.URL; import java.net.URL;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.maxmind.geoip.Location; import com.maxmind.geoip.Location;
import com.maxmind.geoip.LookupService; import com.maxmind.geoip.LookupService;
@ -14,27 +17,30 @@ import com.maxmind.geoip.LookupService;
*/ */
public class IpGeoDB { // change public class IpGeoDB { // change
static{ private static Logger logger = LoggerFactory.getLogger(IpGeoDB.class);
try {
File file = null;
try {
String dir = System.getProperty("user.dir"); static {
String fileName = dir + "/config/GeoLiteCity.dat"; try {
file = new File(fileName); File file = null;
if (!file.exists()){ try {
URL geiIpDBFile = ClassLoader.getSystemResource("GeoLiteCity.dat");
file = new File(geiIpDBFile.toURI()); String dir = System.getProperty("user.dir");
} String fileName = dir + "/config/GeoLiteCity.dat";
} catch (Throwable th) { file = new File(fileName);
th.printStackTrace(); if (!file.exists()) {
System.exit(-1); URL geiIpDBFile = ClassLoader
} .getSystemResource("GeoLiteCity.dat");
cl = new LookupService(file); file = new File(geiIpDBFile.toURI());
} catch (Throwable e) { }
e.printStackTrace(); } catch (Throwable th) {
} logger.error(th.getMessage(), th);
} System.exit(-1);
}
cl = new LookupService(file);
} catch (Throwable e) {
logger.error(e.getMessage(), e);
}
}
private static LookupService cl; private static LookupService cl;
@ -42,9 +48,8 @@ public class IpGeoDB { // change
try { try {
return cl.getLocation(ip); return cl.getLocation(ip);
} catch (Throwable e) { } catch (Throwable e) {
// todo: think about this exception, maybe you can do something more reasonable // TODO: think about this exception, maybe you can do something more reasonable
System.out.println(e.getMessage()); logger.error(e.getMessage(), e);
// e.printStackTrace();
} }
return null; return null;
} }

View File

@ -22,17 +22,16 @@ import java.math.BigInteger;
import java.net.URL; import java.net.URL;
import java.util.Collection; import java.util.Collection;
/** /**
* www.ethereumJ.com * www.ethereumJ.com
* User: Roman Mandeleil * User: Roman Mandeleil
* Created on: 18/05/14 22:21 * Created on: 18/05/14 22:21
*/ */
class ContractSubmitDialog extends JDialog implements MessageAwareDialog{ class ContractSubmitDialog extends JDialog implements MessageAwareDialog {
private static final long serialVersionUID = -3622984456084608996L;
ContractSubmitDialog dialog; ContractSubmitDialog dialog;
JComboBox<AddressStateWraper> creatorAddressCombo; JComboBox<AddressStateWraper> creatorAddressCombo;
final JTextField gasInput; final JTextField gasInput;
final JTextField contractAddrInput; final JTextField contractAddrInput;
@ -101,7 +100,6 @@ class ContractSubmitDialog extends JDialog implements MessageAwareDialog{
}} }}
); );
JLabel statusMessage = new JLabel(""); JLabel statusMessage = new JLabel("");
statusMessage.setBounds(50, 360, 400, 50); statusMessage.setBounds(50, 360, 400, 50);
statusMessage.setHorizontalAlignment(SwingConstants.CENTER); statusMessage.setHorizontalAlignment(SwingConstants.CENTER);
@ -291,8 +289,6 @@ class ContractSubmitDialog extends JDialog implements MessageAwareDialog{
} }
public static void main(String args[]) { public static void main(String args[]) {
AccountState as = new AccountState(); AccountState as = new AccountState();
@ -319,8 +315,7 @@ class ContractSubmitDialog extends JDialog implements MessageAwareDialog{
String valueShort = Utils.getValueShortString(addressState.getBalance()); String valueShort = Utils.getValueShortString(addressState.getBalance());
String result = String result =
String.format(" By: [%s] %s", String.format(" By: [%s] %s", addressShort, valueShort);
addressShort, valueShort);
return result; return result;
} }

View File

@ -4,8 +4,11 @@ import org.ethereum.core.Transaction;
import org.ethereum.manager.MainData; import org.ethereum.manager.MainData;
import org.ethereum.net.submit.TransactionExecutor; import org.ethereum.net.submit.TransactionExecutor;
import org.ethereum.net.submit.TransactionTask; import org.ethereum.net.submit.TransactionTask;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.swing.*; import javax.swing.*;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future; import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
@ -18,13 +21,14 @@ import static org.ethereum.config.SystemProperties.CONFIG;
* User: Roman Mandeleil * User: Roman Mandeleil
* Created on: 26/05/2014 12:27 * Created on: 26/05/2014 12:27
*/ */
public class DialogWorker extends SwingWorker { public class DialogWorker extends SwingWorker {
Transaction tx; private static Logger logger = LoggerFactory.getLogger(DialogWorker.class);
MessageAwareDialog dialog;
DialogWorker(Transaction tx, MessageAwareDialog dialog) { private Transaction tx;
private MessageAwareDialog dialog;
public DialogWorker(Transaction tx, MessageAwareDialog dialog) {
this.tx = tx; this.tx = tx;
this.dialog = dialog; this.dialog = dialog;
} }
@ -32,21 +36,21 @@ public class DialogWorker extends SwingWorker {
@Override @Override
protected Object doInBackground() throws Exception { protected Object doInBackground() throws Exception {
TransactionTask transactionTask = new TransactionTask(tx); TransactionTask transactionTask = new TransactionTask(tx);
Future future = TransactionExecutor.instance.submitTransaction(transactionTask); Future<Transaction> future = TransactionExecutor.instance.submitTransaction(transactionTask);
dialog.infoStatusMsg("Transaction sent to the network, waiting for approve"); dialog.infoStatusMsg("Transaction sent to the network, waiting for approve");
try { try {
future.get(CONFIG.transactionApproveTimeout(), TimeUnit.SECONDS); future.get(CONFIG.transactionApproveTimeout(), TimeUnit.SECONDS);
} catch (TimeoutException e1) { } catch (TimeoutException toe) {
e1.printStackTrace(); logger.error(toe.getMessage(), toe);
dialog.alertStatusMsg("Transaction wasn't approved, network timeout"); dialog.alertStatusMsg("Transaction wasn't approved, network timeout");
return null; return null;
} catch (InterruptedException e1) { } catch (InterruptedException ie) {
e1.printStackTrace(); logger.error(ie.getMessage(), ie);
dialog.alertStatusMsg("Transaction wasn't approved"); dialog.alertStatusMsg("Transaction wasn't approved");
return null; return null;
} catch (ExecutionException e1) { } catch (ExecutionException ee) {
e1.printStackTrace(); logger.error(ee.getMessage(), ee);
dialog.alertStatusMsg("Transaction wasn't approved"); dialog.alertStatusMsg("Transaction wasn't approved");
return null; return null;
} finally { } finally {

View File

@ -1,16 +1,12 @@
package org.ethereum.gui; package org.ethereum.gui;
import javax.swing.*;
import java.awt.*;
/** /**
* www.ethereumJ.com * This interface describes the methods required
* User: Roman Mandeleil * for any dialog that displays info- and alert status messages.
* Created on: 26/05/2014 12:29
*/ */
public interface MessageAwareDialog { public interface MessageAwareDialog {
public void infoStatusMsg(final String text);
public void alertStatusMsg(final String text);
public void infoStatusMsg(final String text);
public void alertStatusMsg(final String text);
} }

View File

@ -22,12 +22,14 @@ import javax.swing.*;
* User: Roman Mandeleil * User: Roman Mandeleil
* Created on: 18/05/14 22:21 * Created on: 18/05/14 22:21
*/ */
class PayOutDialog extends JDialog implements MessageAwareDialog{ class PayOutDialog extends JDialog implements MessageAwareDialog {
PayOutDialog dialog; private static final long serialVersionUID = -2838121935782110981L;
AccountState addressState = null; private PayOutDialog dialog;
JLabel statusMsg = null;
private AccountState addressState = null;
private JLabel statusMsg = null;
final JTextField receiverInput; final JTextField receiverInput;
final JTextField amountInput; final JTextField amountInput;
@ -124,7 +126,6 @@ class PayOutDialog extends JDialog implements MessageAwareDialog{
try { try {
tx.sign(senderPrivKey); tx.sign(senderPrivKey);
} catch (Exception e1) { } catch (Exception e1) {
dialog.alertStatusMsg("Failed to sign the transaction"); dialog.alertStatusMsg("Failed to sign the transaction");
return; return;
} }

View File

@ -1,8 +1,6 @@
package org.ethereum.gui; package org.ethereum.gui;
import org.ethereum.vm.DataWord;
import org.ethereum.vm.Program; import org.ethereum.vm.Program;
import org.ethereum.vm.ProgramInvoke;
import org.ethereum.vm.VM; import org.ethereum.vm.VM;
import org.spongycastle.util.encoders.Hex; import org.spongycastle.util.encoders.Hex;
@ -12,7 +10,6 @@ import javax.swing.event.ChangeListener;
import java.awt.*; import java.awt.*;
import java.awt.event.ActionEvent; import java.awt.event.ActionEvent;
import java.awt.event.ActionListener; import java.awt.event.ActionListener;
import java.awt.event.WindowListener;
import java.util.*; import java.util.*;
import java.util.List; import java.util.List;
@ -22,7 +19,8 @@ import java.util.List;
* Created on: 02/06/2014 16:58 * Created on: 02/06/2014 16:58
*/ */
public class ProgramPlayDialog extends JPanel implements ActionListener, ChangeListener, Program.ProgramListener { public class ProgramPlayDialog extends JPanel implements ActionListener,
ChangeListener, Program.ProgramListener {
public List<String> outputList; public List<String> outputList;
public JTextArea console; public JTextArea console;
@ -95,8 +93,6 @@ public class ProgramPlayDialog extends JPanel implements ActionListener, ChangeL
@Override @Override
public void actionPerformed(ActionEvent e) { public void actionPerformed(ActionEvent e) {
} }
@Override @Override
@ -111,7 +107,6 @@ public class ProgramPlayDialog extends JPanel implements ActionListener, ChangeL
console.setCaretPosition(0); console.setCaretPosition(0);
} }
/** /**
* Create the GUI and show it. For thread safety, * Create the GUI and show it. For thread safety,
* this method should be invoked from the * this method should be invoked from the
@ -119,8 +114,6 @@ public class ProgramPlayDialog extends JPanel implements ActionListener, ChangeL
*/ */
public static void createAndShowGUI() { public static void createAndShowGUI() {
ProgramPlayDialog ppd = new ProgramPlayDialog(); ProgramPlayDialog ppd = new ProgramPlayDialog();
//Create and set up the window. //Create and set up the window.
@ -130,7 +123,6 @@ public class ProgramPlayDialog extends JPanel implements ActionListener, ChangeL
frame.setPreferredSize(new Dimension(580, 500)); frame.setPreferredSize(new Dimension(580, 500));
frame.setLocation(400, 200); frame.setLocation(400, 200);
//Add content to the window. //Add content to the window.
frame.add(ppd, BorderLayout.CENTER); frame.add(ppd, BorderLayout.CENTER);
@ -138,7 +130,6 @@ public class ProgramPlayDialog extends JPanel implements ActionListener, ChangeL
frame.pack(); frame.pack();
frame.setVisible(true); frame.setVisible(true);
ppd.setFocus(); ppd.setFocus();
} }
@Override @Override
@ -151,10 +142,9 @@ public class ProgramPlayDialog extends JPanel implements ActionListener, ChangeL
/* Turn off metal's use of bold fonts */ /* Turn off metal's use of bold fonts */
UIManager.put("swing.boldMetal", Boolean.FALSE); UIManager.put("swing.boldMetal", Boolean.FALSE);
//Schedule a job for the event-dispatching thread: //Schedule a job for the event-dispatching thread:
//creating and showing this application's GUI. //creating and showing this application's GUI.
javax.swing.SwingUtilities.invokeLater(new Runnable() { SwingUtilities.invokeLater(new Runnable() {
public void run() { public void run() {
createAndShowGUI(); createAndShowGUI();
} }

View File

@ -16,7 +16,7 @@ public class StaticMessages {
public static final byte[] GET_TRANSACTIONS = Hex.decode("2240089100000002C116"); public static final byte[] GET_TRANSACTIONS = Hex.decode("2240089100000002C116");
public static final byte[] DISCONNECT_08 = Hex.decode("2240089100000003C20108"); public static final byte[] DISCONNECT_08 = Hex.decode("2240089100000003C20108");
public static final byte[] GENESIS_HASH = Hex.decode("77ef4fdaf389dca53236bcf7f72698e154eab2828f86fbc4fc6cd9225d285c89"); // (new Genesis()).getHash(); public static final byte[] GENESIS_HASH = Hex.decode("77ef4fdaf389dca53236bcf7f72698e154eab2828f86fbc4fc6cd9225d285c89");
public static final byte[] MAGIC_PACKET = Hex.decode("22400891"); public static final byte[] MAGIC_PACKET = Hex.decode("22400891");
static { static {

View File

@ -10,14 +10,16 @@ import org.ethereum.core.Transaction;
public class PendingTransaction { public class PendingTransaction {
Transaction tx; private Transaction tx;
int approved = 0; // each time the tx got from the wire this value increased int approved = 0; // each time the tx got from the wire this value increased
public PendingTransaction(Transaction tx) { public PendingTransaction(Transaction tx) {
this.tx = tx; this.tx = tx;
} }
public void incApproved(){++this.approved;} public void incApproved() {
++this.approved;
}
public int getApproved() { public int getApproved() {
return approved; return approved;

View File

@ -7,12 +7,12 @@ import static org.ethereum.util.CompactEncoder.unpackToNibbles;
public class TrieIterator { public class TrieIterator {
Trie trie; private Trie trie;
String key; private String key;
String value; private String value;
List<byte[]> shas; private List<byte[]> shas;
List<String> values; private List<String> values;
public TrieIterator(Trie t) { public TrieIterator(Trie t) {
this.trie = t; this.trie = t;

View File

@ -7,34 +7,31 @@ import java.math.BigInteger;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
/** /**
* www.ethereumJ.com * DataWord is the 32-byte array representation of a 256-bit number
* User: Roman Mandeleil * Calculations can be done on this word with other DataWords
* Created on: 01/06/2014 19:47
*/ */
public class DataWord { public class DataWord {
static DataWord ZERO = new DataWord(new byte[32]); // don't push it in to the stack static DataWord ZERO = new DataWord(new byte[32]); // don't push it in to the stack
byte[] data = new byte[32]; byte[] data = new byte[32];
public DataWord(){ public DataWord() {
data = new byte[32]; data = new byte[32];
} }
public DataWord(int num){ public DataWord(int num) {
ByteBuffer bInt = ByteBuffer.allocate(4).putInt(num); ByteBuffer bInt = ByteBuffer.allocate(4).putInt(num);
ByteBuffer data = ByteBuffer.allocate(32); ByteBuffer data = ByteBuffer.allocate(32);
System.arraycopy(bInt.array(), 0, data.array(), 28, 4); System.arraycopy(bInt.array(), 0, data.array(), 28, 4);
this.data = data.array(); this.data = data.array();
} }
public DataWord(byte[] data){ public DataWord(byte[] data) {
if (data == null || data.length > 32) if (data == null || data.length > 32)
throw new RuntimeException("bad push data: " + data); throw new RuntimeException("bad push data: " + data);
System.arraycopy(data, 0, this.data, 32 - data.length, data.length);
System.arraycopy(data, 0, this.data, 32 - data.length, data.length); }
}
public byte[] getData() { public byte[] getData() {
return data; return data;
@ -95,9 +92,20 @@ public class DataWord {
} }
} }
// todo: add can be done in more efficient way // By : Holger
// todo without BigInteger quick hack // From : http://stackoverflow.com/a/24023466/459349
public void add(DataWord word){ public void add(DataWord word) {
byte[] result = new byte[32];
for (int i = 31, overflow = 0; i >= 0; i--) {
int v = (this.data[i] & 0xff) + (word.data[i] & 0xff) + overflow;
result[i] = (byte) v;
overflow = v >>> 8;
}
this.data = result;
}
// old add-method with BigInteger quick hack
public void add2(DataWord word){
BigInteger result = value().add( word.value() ); BigInteger result = value().add( word.value() );
byte[] bytes = result.toByteArray(); byte[] bytes = result.toByteArray();
@ -107,10 +115,10 @@ public class DataWord {
this.data = data.array(); this.data = data.array();
} }
// todo: mull can be done in more efficient way // todo: mul can be done in more efficient way
// todo: with shift left shift right trick // todo: with shift left shift right trick
// todo without BigInteger quick hack // todo without BigInteger quick hack
public void mull(DataWord word){ public void mul(DataWord word){
BigInteger result = value().multiply( word.value() ); BigInteger result = value().multiply( word.value() );
byte[] bytes = result.toByteArray(); byte[] bytes = result.toByteArray();

View File

@ -55,7 +55,7 @@ public class VM {
DataWord word1 = program.stackPop(); DataWord word1 = program.stackPop();
DataWord word2 = program.stackPop(); DataWord word2 = program.stackPop();
word1.mull(word2); word1.mul(word2);
program.stackPush(word1); program.stackPush(word1);
program.step(); program.step();
} }

View File

@ -69,4 +69,4 @@ samples.dir = samples
# the existing database will be # the existing database will be
# destroyed and all the data will be # destroyed and all the data will be
# downloaded from peers again # downloaded from peers again
database.reset = true database.reset = false

View File

@ -22,7 +22,7 @@ public class BlockTest {
// from RLP encoding // from RLP encoding
byte[] genesisBytes = Hex.decode(CPP_PoC5_GENESIS_HEX_RLP_ENCODED); byte[] genesisBytes = Hex.decode(CPP_PoC5_GENESIS_HEX_RLP_ENCODED);
Block genesisFromRLP = new Block(genesisBytes); Block genesisFromRLP = new Block(genesisBytes);
Genesis genesis = new Genesis(); Block genesis = Genesis.getInstance();
assertEquals(Hex.toHexString(genesis.getHash()), Hex.toHexString(genesisFromRLP.getHash())); assertEquals(Hex.toHexString(genesis.getHash()), Hex.toHexString(genesisFromRLP.getHash()));
assertEquals(Hex.toHexString(genesis.getParentHash()), Hex.toHexString(genesisFromRLP.getParentHash())); assertEquals(Hex.toHexString(genesis.getParentHash()), Hex.toHexString(genesisFromRLP.getParentHash()));
assertEquals(Hex.toHexString(genesis.getStateRoot()), Hex.toHexString(genesisFromRLP.getStateRoot())); assertEquals(Hex.toHexString(genesis.getStateRoot()), Hex.toHexString(genesisFromRLP.getStateRoot()));
@ -48,7 +48,7 @@ public class BlockTest {
B32(sha3(B(42))) B32(sha3(B(42)))
) )
*/ */
Block genesis = new Genesis(); Block genesis = Genesis.getInstance();
assertEquals(CPP_PoC5_GENESIS_HEX_RLP_ENCODED, Hex.toHexString(genesis.getEncoded())); assertEquals(CPP_PoC5_GENESIS_HEX_RLP_ENCODED, Hex.toHexString(genesis.getEncoded()));
// Not really a good test because this compares Genesis.getHash() to itself // Not really a good test because this compares Genesis.getHash() to itself

View File

@ -0,0 +1,71 @@
package org.ethereum.vm;
import static org.junit.Assert.*;
import org.junit.Test;
import org.spongycastle.util.encoders.Hex;
public class DataWordTest {
@Test
public void testAddPerformance() {
boolean enabled = true;
if(enabled) {
byte[] one = new byte[] { 0x01, 0x31, 0x54, 0x41, 0x01, 0x31, 0x54,
0x41, 0x01, 0x31, 0x54, 0x41, 0x01, 0x31, 0x54, 0x41, 0x01,
0x31, 0x54, 0x41, 0x01, 0x31, 0x54, 0x41, 0x01, 0x31, 0x54,
0x41, 0x01, 0x31, 0x54, 0x41 }; // Random value
int ITERATIONS = 10000000;
long now1 = System.currentTimeMillis();
for (int i = 0; i < ITERATIONS; i++) {
DataWord x = new DataWord(one);
x.add(x);
}
System.out.println("Add1: " + (System.currentTimeMillis() - now1) + "ms");
long now2 = System.currentTimeMillis();
for (int i = 0; i < ITERATIONS; i++) {
DataWord x = new DataWord(one);
x.add2(x);
}
System.out.println("Add2: " + (System.currentTimeMillis() - now2) + "ms");
} else {
System.out.println("ADD performance test is disabled.");
}
}
@Test
public void testAdd2() {
byte[] two = new byte[32];
two[31] = (byte) 0xff; // 0x000000000000000000000000000000000000000000000000000000000000ff
DataWord x = new DataWord(two);
x.add(new DataWord(two));
System.out.println(Hex.toHexString(x.data));
DataWord y = new DataWord(two);
y.add2(new DataWord(two));
System.out.println(Hex.toHexString(y.data));
}
@Test
public void testAdd3() {
byte[] three = new byte[32];
for (int i = 0; i < three.length; i++) {
three[i] = (byte) 0xff;
}
DataWord x = new DataWord(three);
x.add(new DataWord(three));
assertEquals(32, x.data.length);
System.out.println(Hex.toHexString(x.data));
// FAIL
// DataWord y = new DataWord(three);
// y.add2(new DataWord(three));
// System.out.println(Hex.toHexString(y.data));
}
}

View File

@ -4,8 +4,6 @@ import org.ethereum.crypto.ECKey;
import org.ethereum.crypto.HashUtil; import org.ethereum.crypto.HashUtil;
import org.spongycastle.util.encoders.Hex; import org.spongycastle.util.encoders.Hex;
import java.util.List;
/** /**
* www.ethereumJ.com * www.ethereumJ.com
* User: Roman Mandeleil * User: Roman Mandeleil

View File

@ -1,6 +1,5 @@
package org.ethereum.vm; package org.ethereum.vm;
import org.ethereum.crypto.HashUtil;
import org.junit.Test; import org.junit.Test;
import org.spongycastle.util.encoders.Hex; import org.spongycastle.util.encoders.Hex;