diff --git a/ethereumj-core/src/main/java/org/ethereum/core/Account.java b/ethereumj-core/src/main/java/org/ethereum/core/Account.java new file mode 100644 index 00000000..017afa29 --- /dev/null +++ b/ethereumj-core/src/main/java/org/ethereum/core/Account.java @@ -0,0 +1,51 @@ +package org.ethereum.core; + +import java.math.BigInteger; + +import org.ethereum.crypto.ECKey; +import org.ethereum.util.Utils; + +/** + * Representation of an actual account or contract + */ +public class Account { + + private ECKey ecKey; + private byte[] address; + private AccountState state; + + public Account() { + this.ecKey = new ECKey(Utils.getRandom()); + this.state = new AccountState(); + } + + public Account(ECKey ecKey) { + this.ecKey = ecKey; + this.state = new AccountState(); + } + + public Account(ECKey ecKey, BigInteger nonce, BigInteger balance) { + this.ecKey = ecKey; + this.state = new AccountState(nonce, balance); + } + + public ECKey getEcKey() { + return ecKey; + } + + public byte[] getAddress() { + return address; + } + + public void setAddress(byte[] address) { + this.address = address; + } + + public AccountState getState() { + return state; + } + + public void setState(AccountState state) { + this.state = state; + } +} diff --git a/ethereumj-core/src/main/java/org/ethereum/core/AccountState.java b/ethereumj-core/src/main/java/org/ethereum/core/AccountState.java index 293787a9..29417ae4 100644 --- a/ethereumj-core/src/main/java/org/ethereum/core/AccountState.java +++ b/ethereumj-core/src/main/java/org/ethereum/core/AccountState.java @@ -1,16 +1,13 @@ package org.ethereum.core; -import org.ethereum.crypto.ECKey; import org.ethereum.crypto.HashUtil; import org.ethereum.util.RLP; import org.ethereum.util.RLPList; -import org.ethereum.util.Utils; import java.math.BigInteger; public class AccountState { - private ECKey ecKey; private byte[] rlpEncoded; /* A value equal to the number of transactions sent @@ -42,39 +39,26 @@ public class AccountState { private byte[] codeHash = HashUtil.sha3(new byte[0]); public AccountState() { - this(new ECKey(Utils.getRandom())); + this(BigInteger.ZERO, BigInteger.ZERO); } - public AccountState(ECKey ecKey) { - this(ecKey, BigInteger.ZERO, BigInteger.ZERO); + public AccountState(BigInteger nonce, BigInteger balance) { + this.nonce = nonce; + this.balance = balance; } - + public AccountState(byte[] rlpData) { this.rlpEncoded = rlpData; RLPList items = (RLPList) RLP.decode2(rlpEncoded).get(0); this.nonce = new BigInteger(1, ((items.get(0).getRLPData()) == null ? new byte[]{0} : items.get(0).getRLPData())); - this.balance = new BigInteger(1, items.get(1).getRLPData()); + this.balance = new BigInteger(1, ((items.get(1).getRLPData()) == null ? new byte[]{0} : + items.get(1).getRLPData())); this.stateRoot = items.get(2).getRLPData(); this.codeHash = items.get(3).getRLPData(); } - public AccountState(ECKey ecKey, BigInteger nonce, BigInteger balance) { - this.ecKey = ecKey; - this.nonce = nonce; - this.balance = balance; - } - - public AccountState(BigInteger nonce, BigInteger balance) { - this.nonce = nonce; - this.balance = balance; - } - - public ECKey getEcKey() { - return ecKey; - } - public BigInteger getNonce() { return nonce; } diff --git a/ethereumj-core/src/main/java/org/ethereum/core/Block.java b/ethereumj-core/src/main/java/org/ethereum/core/Block.java index bde2061f..f0fb6809 100644 --- a/ethereumj-core/src/main/java/org/ethereum/core/Block.java +++ b/ethereumj-core/src/main/java/org/ethereum/core/Block.java @@ -56,7 +56,7 @@ public class Block { difficulty, number, minGasPrice, gasLimit, gasUsed, timestamp, extraData, nonce); this.txsState = new Trie(null); - this.header.setStateRoot(WorldManager.instance.allAccountsState.getRootHash()); + this.header.setStateRoot(WorldManager.instance.worldState.getRootHash()); this.header.setTxTrieRoot(txsState.getRootHash()); this.transactionsList = transactionsList; this.uncleList = uncleList; @@ -275,8 +275,8 @@ public class Block { public byte[] updateState(byte[] key, byte[] value) { - WorldManager.instance.allAccountsState.update(key, value); - byte[] stateRoot = WorldManager.instance.allAccountsState.getRootHash(); + WorldManager.instance.worldState.update(key, value); + byte[] stateRoot = WorldManager.instance.worldState.getRootHash(); this.header.setStateRoot(stateRoot); return stateRoot; } diff --git a/ethereumj-core/src/main/java/org/ethereum/core/Blockchain.java b/ethereumj-core/src/main/java/org/ethereum/core/Blockchain.java index 11675bdc..11ddcaf7 100644 --- a/ethereumj-core/src/main/java/org/ethereum/core/Blockchain.java +++ b/ethereumj-core/src/main/java/org/ethereum/core/Blockchain.java @@ -18,7 +18,7 @@ public class Blockchain extends ArrayList { private static final long serialVersionUID = -143590724563460486L; - private static Logger logger = LoggerFactory.getLogger(Blockchain.class); + private static Logger logger = LoggerFactory.getLogger("Chain"); // to avoid using minGasPrice=0 from Genesis for the wallet private static long INITIAL_MIN_GAS_PRICE = 10 * SZABO.longValue(); diff --git a/ethereumj-core/src/main/java/org/ethereum/core/Transaction.java b/ethereumj-core/src/main/java/org/ethereum/core/Transaction.java index 6519264c..3afe22e2 100644 --- a/ethereumj-core/src/main/java/org/ethereum/core/Transaction.java +++ b/ethereumj-core/src/main/java/org/ethereum/core/Transaction.java @@ -12,7 +12,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.spongycastle.util.BigIntegers; -import java.math.BigInteger; import java.security.SignatureException; import java.util.Arrays; diff --git a/ethereumj-core/src/main/java/org/ethereum/core/Wallet.java b/ethereumj-core/src/main/java/org/ethereum/core/Wallet.java index de7da49f..ab5261fd 100644 --- a/ethereumj-core/src/main/java/org/ethereum/core/Wallet.java +++ b/ethereumj-core/src/main/java/org/ethereum/core/Wallet.java @@ -23,9 +23,8 @@ import java.util.HashMap; import java.util.List; /** - * www.ethereumJ.com - * User: Roman Mandeleil - * Created on: 17/05/14 15:53 + * The Wallet handles the management of accounts with addresses and private keys. + * New accounts can be generated and added to the wallet and existing accounts can be queried. */ public class Wallet { @@ -34,24 +33,24 @@ public class Wallet { // private HashMap rows = new HashMap<>(); // table for a wallet - private HashMap rows = new HashMap(); + private HashMap rows = new HashMap(); private long high; private List listeners = new ArrayList(); private HashMap transactionMap = new HashMap(); - public void addNewKey(){ - AccountState addressState = new AccountState(); - String address = Hex.toHexString(addressState.getEcKey().getAddress()); - rows.put(address, addressState); + public void addNewAccount() { + Account account = new Account(); + String address = Hex.toHexString(account.getEcKey().getAddress()); + rows.put(address, account); for (WalletListener listener : listeners) listener.valueChanged(); } public void importKey(byte[] privKey){ - AccountState addressState = new AccountState(ECKey.fromPrivate(privKey)); - String address = Hex.toHexString(addressState.getEcKey().getAddress()); - rows.put(address, addressState); + Account account = new Account(ECKey.fromPrivate(privKey)); + String address = Hex.toHexString(account.getEcKey().getAddress()); + rows.put(address, account); notifyListeners(); } @@ -59,24 +58,24 @@ public class Wallet { this.listeners.add(walletListener); } - public Collection getAddressStateCollection(){ + public Collection getAccountCollection(){ return rows.values(); } - public AccountState getAddressState(byte[] addressBytes){ + public AccountState getAccountState(byte[] addressBytes){ String address = Hex.toHexString(addressBytes); - return rows.get(address); + return rows.get(address).getState(); } public BigInteger getBalance(byte[] addressBytes){ String address = Hex.toHexString(addressBytes); - return rows.get(address).getBalance(); + return rows.get(address).getState().getBalance(); } public BigInteger totalBalance(){ BigInteger sum = BigInteger.ZERO; - for (AccountState addressState : rows.values()){ - sum = sum.add(addressState.getBalance()); + for (Account account : rows.values()){ + sum = sum.add(account.getState().getBalance()); } return sum; } @@ -86,18 +85,18 @@ public class Wallet { transactionMap.put(new BigInteger(transaction.getHash()), transaction ); byte[] senderAddress = transaction.getSender(); - AccountState senderState = rows.get(Hex.toHexString(senderAddress)); - if (senderState != null){ + Account sender = rows.get(Hex.toHexString(senderAddress)); + if (sender != null){ BigInteger value = new BigInteger(-1, transaction.getValue()); - senderState.addToBalance(value); - senderState.incrementNonce(); + sender.getState().addToBalance(value); + sender.getState().incrementNonce(); } byte[] receiveAddress = transaction.getReceiveAddress(); - AccountState receiverState = rows.get(Hex.toHexString(receiveAddress)); - if (receiverState != null){ - receiverState.addToBalance(new BigInteger(1, transaction.getValue())); + Account receiver = rows.get(Hex.toHexString(receiveAddress)); + if (receiver != null){ + receiver.getState().addToBalance(new BigInteger(1, transaction.getValue())); } notifyListeners(); @@ -214,7 +213,7 @@ public class Wallet { walletElement.setAttributeNode(high); int i = 0; - for (AccountState addressState : getAddressStateCollection()){ + for (Account account : getAccountCollection()){ Element raw = doc.createElement("raw"); Attr id = doc.createAttribute("id"); @@ -222,17 +221,17 @@ public class Wallet { raw.setAttributeNode(id); Element addressE = doc.createElement("address"); - addressE.setTextContent(Hex.toHexString(addressState.getEcKey().getAddress())); + addressE.setTextContent(Hex.toHexString(account.getEcKey().getAddress())); Attr nonce = doc.createAttribute("nonce"); nonce.setValue("0"); addressE.setAttributeNode(nonce); Element privKey = doc.createElement("privkey"); - privKey.setTextContent(Hex.toHexString(addressState.getEcKey().getPrivKeyBytes())); + privKey.setTextContent(Hex.toHexString(account.getEcKey().getPrivKeyBytes())); Element value = doc.createElement("value"); - value.setTextContent(addressState.getBalance().toString()); + value.setTextContent(account.getState().getBalance().toString()); raw.appendChild(addressE); raw.appendChild(privKey); diff --git a/ethereumj-core/src/main/java/org/ethereum/gui/ContractCallDialog.java b/ethereumj-core/src/main/java/org/ethereum/gui/ContractCallDialog.java index cc3b5f12..0caf4560 100644 --- a/ethereumj-core/src/main/java/org/ethereum/gui/ContractCallDialog.java +++ b/ethereumj-core/src/main/java/org/ethereum/gui/ContractCallDialog.java @@ -1,6 +1,6 @@ package org.ethereum.gui; -import org.ethereum.core.AccountState; +import org.ethereum.core.Account; import org.ethereum.core.Transaction; import org.ethereum.manager.MainData; import org.ethereum.net.client.ClientPeer; @@ -36,7 +36,7 @@ class ContractCallDialog extends JDialog implements MessageAwareDialog{ ContractCallDialog dialog; - JComboBox creatorAddressCombo; + JComboBox creatorAddressCombo; final JTextField gasInput; final JTextField contractAddrInput; JTextArea msgDataTA; @@ -116,7 +116,7 @@ class ContractCallDialog extends JDialog implements MessageAwareDialog{ gasInput.setText("1000"); - JComboBox creatorAddressCombo = new JComboBox() { + JComboBox creatorAddressCombo = new JComboBox() { @Override public ComboBoxUI getUI() { BasicComboBoxUI ui = (BasicComboBoxUI) super.getUI(); @@ -135,11 +135,11 @@ class ContractCallDialog extends JDialog implements MessageAwareDialog{ JComponent editor = (JComponent)(creatorAddressCombo.getEditor().getEditorComponent()); editor.setForeground(Color.RED); - Collection addressStates = - MainData.instance.getWallet().getAddressStateCollection(); + Collection accounts = + MainData.instance.getWallet().getAccountCollection(); - for (AccountState addressState : addressStates){ - creatorAddressCombo.addItem(new AddressStateWraper(addressState)); + for (Account account : accounts){ + creatorAddressCombo.addItem(new AccountWrapper(account)); } creatorAddressCombo.setRenderer(new DefaultListCellRenderer() { @@ -229,10 +229,10 @@ class ContractCallDialog extends JDialog implements MessageAwareDialog{ byte[] contractAddress = Hex.decode( contractAddrInput.getText()); - AccountState addressState = ((AddressStateWraper)creatorAddressCombo.getSelectedItem()).getAddressState(); + Account account = ((AccountWrapper)creatorAddressCombo.getSelectedItem()).getAccount(); - byte[] senderPrivKey = addressState.getEcKey().getPrivKeyBytes(); - byte[] nonce = addressState.getNonce() == BigInteger.ZERO ? null : addressState.getNonce().toByteArray(); + byte[] senderPrivKey = account.getEcKey().getPrivKeyBytes(); + byte[] nonce = account.getState().getNonce() == BigInteger.ZERO ? null : account.getState().getNonce().toByteArray(); byte[] gasPrice = new BigInteger("10000000000000").toByteArray(); BigInteger gasBI = new BigInteger(gasInput.getText()); @@ -269,22 +269,22 @@ class ContractCallDialog extends JDialog implements MessageAwareDialog{ worker.execute(); } - public class AddressStateWraper { + public class AccountWrapper { - private AccountState addressState; + private Account account; - public AddressStateWraper(AccountState addressState) { - this.addressState = addressState; + public AccountWrapper(Account account) { + this.account = account; } - public AccountState getAddressState() { - return addressState; + public Account getAccount() { + return account; } @Override public String toString() { - String addressShort = Utils.getAddressShortString(addressState.getEcKey().getAddress()); - String valueShort = Utils.getValueShortString(addressState.getBalance()); + String addressShort = Utils.getAddressShortString(account.getEcKey().getAddress()); + String valueShort = Utils.getValueShortString(account.getState().getBalance()); String result = String.format(" By: [%s] %s", addressShort, valueShort); return result; diff --git a/ethereumj-core/src/main/java/org/ethereum/gui/ContractSubmitDialog.java b/ethereumj-core/src/main/java/org/ethereum/gui/ContractSubmitDialog.java index d9c9dde0..7e22911a 100644 --- a/ethereumj-core/src/main/java/org/ethereum/gui/ContractSubmitDialog.java +++ b/ethereumj-core/src/main/java/org/ethereum/gui/ContractSubmitDialog.java @@ -1,5 +1,6 @@ package org.ethereum.gui; +import org.ethereum.core.Account; import org.ethereum.core.AccountState; import org.ethereum.core.Transaction; import org.ethereum.manager.MainData; @@ -32,7 +33,7 @@ class ContractSubmitDialog extends JDialog implements MessageAwareDialog { private static final long serialVersionUID = -3622984456084608996L; ContractSubmitDialog dialog; - JComboBox creatorAddressCombo; + JComboBox creatorAddressCombo; final JTextField gasInput; final JTextField contractAddrInput; @@ -139,7 +140,7 @@ class ContractSubmitDialog extends JDialog implements MessageAwareDialog { gasInput.setText("1000"); - JComboBox creatorAddressCombo = new JComboBox(){ + JComboBox creatorAddressCombo = new JComboBox(){ @Override public ComboBoxUI getUI() { @@ -160,12 +161,11 @@ class ContractSubmitDialog extends JDialog implements MessageAwareDialog { JComponent editor = (JComponent)(creatorAddressCombo.getEditor().getEditorComponent()); editor.setForeground(Color.RED); - Collection addressStates = - MainData.instance.getWallet().getAddressStateCollection(); + Collection accounts = + MainData.instance.getWallet().getAccountCollection(); - for (AccountState addressState : addressStates){ - - creatorAddressCombo.addItem(new AddressStateWraper(addressState)); + for (Account account : accounts){ + creatorAddressCombo.addItem(new AccountWrapper(account)); } creatorAddressCombo.setRenderer(new DefaultListCellRenderer() { @@ -251,10 +251,10 @@ class ContractSubmitDialog extends JDialog implements MessageAwareDialog { public void submitContract(){ - AccountState addressState = ((AddressStateWraper)creatorAddressCombo.getSelectedItem()).getAddressState(); + Account account = ((AccountWrapper)creatorAddressCombo.getSelectedItem()).getAccount(); - byte[] senderPrivKey = addressState.getEcKey().getPrivKeyBytes(); - byte[] nonce = addressState.getNonce() == BigInteger.ZERO ? null : addressState.getNonce().toByteArray(); + byte[] senderPrivKey = account.getEcKey().getPrivKeyBytes(); + byte[] nonce = account.getState().getNonce() == BigInteger.ZERO ? null : account.getState().getNonce().toByteArray(); byte[] gasPrice = new BigInteger("10000000000000").toByteArray(); BigInteger gasBI = new BigInteger(gasInput.getText()); @@ -297,22 +297,22 @@ class ContractSubmitDialog extends JDialog implements MessageAwareDialog { pod.setVisible(true); } - public class AddressStateWraper{ + public class AccountWrapper{ - private AccountState addressState; + private Account account; - public AddressStateWraper(AccountState addressState) { - this.addressState = addressState; + public AccountWrapper(Account account) { + this.account = account; } - public AccountState getAddressState() { - return addressState; + public Account getAccount() { + return account; } @Override public String toString() { - String addressShort = Utils.getAddressShortString(addressState.getEcKey().getAddress()); - String valueShort = Utils.getValueShortString(addressState.getBalance()); + String addressShort = Utils.getAddressShortString(account.getEcKey().getAddress()); + String valueShort = Utils.getValueShortString(account.getState().getBalance()); String result = String.format(" By: [%s] %s", addressShort, valueShort); diff --git a/ethereumj-core/src/main/java/org/ethereum/gui/PayOutDialog.java b/ethereumj-core/src/main/java/org/ethereum/gui/PayOutDialog.java index eb76932c..4c1d1ac1 100644 --- a/ethereumj-core/src/main/java/org/ethereum/gui/PayOutDialog.java +++ b/ethereumj-core/src/main/java/org/ethereum/gui/PayOutDialog.java @@ -1,5 +1,6 @@ package org.ethereum.gui; +import org.ethereum.core.Account; import org.ethereum.core.AccountState; import org.ethereum.core.Transaction; import org.ethereum.manager.MainData; @@ -35,11 +36,11 @@ class PayOutDialog extends JDialog implements MessageAwareDialog { final JTextField amountInput; final JTextField feeInput; - public PayOutDialog(Frame parent, final AccountState addressState) { + public PayOutDialog(Frame parent, final Account account) { super(parent, "Payout details: ", false); dialog = this; - this.addressState = addressState; + this.addressState = account.getState(); receiverInput = new JTextField(18); GUIUtils.addStyle(receiverInput, "Pay to:"); @@ -114,7 +115,7 @@ class PayOutDialog extends JDialog implements MessageAwareDialog { return; } - byte[] senderPrivKey = addressState.getEcKey().getPrivKeyBytes(); + byte[] senderPrivKey = account.getEcKey().getPrivKeyBytes(); byte[] nonce = addressState.getNonce() == BigInteger.ZERO ? null : addressState.getNonce().toByteArray(); byte[] gasPrice = BigInteger.valueOf( MainData.instance.getBlockchain().getGasPrice()).toByteArray(); @@ -189,7 +190,6 @@ class PayOutDialog extends JDialog implements MessageAwareDialog { return false; } - // check if the tx is affordable BigInteger ammountValue = new BigInteger(amountText); BigInteger feeValue = new BigInteger(feeText); @@ -261,8 +261,8 @@ class PayOutDialog extends JDialog implements MessageAwareDialog { } public static void main(String args[]) { - AccountState as = new AccountState(); - PayOutDialog pod = new PayOutDialog(null, as); + Account account = new Account(); + PayOutDialog pod = new PayOutDialog(null, account); pod.setVisible(true); } } diff --git a/ethereumj-core/src/main/java/org/ethereum/gui/WalletAddressPanel.java b/ethereumj-core/src/main/java/org/ethereum/gui/WalletAddressPanel.java index c4275f4f..7457d6ad 100644 --- a/ethereumj-core/src/main/java/org/ethereum/gui/WalletAddressPanel.java +++ b/ethereumj-core/src/main/java/org/ethereum/gui/WalletAddressPanel.java @@ -1,5 +1,6 @@ package org.ethereum.gui; +import org.ethereum.core.Account; import org.ethereum.core.AccountState; import org.ethereum.util.Utils; import org.spongycastle.util.encoders.Hex; @@ -21,7 +22,7 @@ import java.net.URL; */ public class WalletAddressPanel extends JPanel{ - public WalletAddressPanel(final AccountState addressState) { + public WalletAddressPanel(final Account account) { 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(addressState.getEcKey().getAddress()).toUpperCase()); + addressField.setText(Hex.toHexString(account.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(addressState.getBalance())); + amount.setText(Utils.getValueShortString(account.getState().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(JFrame.class, - walletAddressPanel), addressState); + walletAddressPanel), account); } }); diff --git a/ethereumj-core/src/main/java/org/ethereum/gui/WalletWindow.java b/ethereumj-core/src/main/java/org/ethereum/gui/WalletWindow.java index 071e33d4..bda46277 100644 --- a/ethereumj-core/src/main/java/org/ethereum/gui/WalletWindow.java +++ b/ethereumj-core/src/main/java/org/ethereum/gui/WalletWindow.java @@ -1,6 +1,6 @@ package org.ethereum.gui; -import org.ethereum.core.AccountState; +import org.ethereum.core.Account; import org.ethereum.core.Wallet; import org.ethereum.manager.MainData; @@ -56,10 +56,9 @@ public class WalletWindow extends JFrame implements Wallet.WalletListener{ Wallet wallet = MainData.instance.getWallet(); - for (AccountState addressState : wallet.getAddressStateCollection()){ + for (Account account : wallet.getAccountCollection()){ - WalletAddressPanel rowPanel = - new WalletAddressPanel(addressState); + WalletAddressPanel rowPanel = new WalletAddressPanel(account); contentPane.add(rowPanel); } @@ -78,13 +77,13 @@ public class WalletWindow extends JFrame implements Wallet.WalletListener{ public void mouseClicked(MouseEvent e) { Wallet wallet = MainData.instance.getWallet(); - if (wallet.getAddressStateCollection().size() >=5){ + if (wallet.getAccountCollection().size() >=5){ JOptionPane.showMessageDialog(walletWindow, "Hey do you really need more than 5 address for a demo wallet"); return; } - wallet.addNewKey(); + wallet.addNewAccount(); Dimension dimension = walletWindow.getSize(); int height = dimension.height; int width = dimension.width; diff --git a/ethereumj-core/src/main/java/org/ethereum/manager/MainData.java b/ethereumj-core/src/main/java/org/ethereum/manager/MainData.java index c2fee63a..88e1d30e 100644 --- a/ethereumj-core/src/main/java/org/ethereum/manager/MainData.java +++ b/ethereumj-core/src/main/java/org/ethereum/manager/MainData.java @@ -47,7 +47,7 @@ public class MainData { ECKey key = ECKey.fromPrivate(cowAddr); wallet.importKey(cowAddr); - AccountState state = wallet.getAddressState(key.getAddress()); + AccountState state = wallet.getAccountState(key.getAddress()); state.addToBalance(BigInteger.valueOf(2).pow(200)); wallet.importKey(HashUtil.sha3("cat".getBytes())); diff --git a/ethereumj-core/src/main/java/org/ethereum/manager/WorldManager.java b/ethereumj-core/src/main/java/org/ethereum/manager/WorldManager.java index 8d2122bc..085b6c49 100644 --- a/ethereumj-core/src/main/java/org/ethereum/manager/WorldManager.java +++ b/ethereumj-core/src/main/java/org/ethereum/manager/WorldManager.java @@ -1,6 +1,5 @@ package org.ethereum.manager; -import io.netty.channel.AddressedEnvelope; import org.ethereum.core.AccountState; import org.ethereum.core.Block; import org.ethereum.core.Transaction; @@ -21,15 +20,12 @@ import java.util.List; import java.util.Map; /** - * www.ethereumJ.com - * User: Roman Mandeleil - * Created on: 07/06/2014 10:08 + * WorldManager is the main class to handle the processing of transactions and managing the world state. */ - public class WorldManager { - Logger logger = LoggerFactory.getLogger("main"); - Logger stateLogger = LoggerFactory.getLogger("state"); + private Logger logger = LoggerFactory.getLogger("main"); + private Logger stateLogger = LoggerFactory.getLogger("state"); public static WorldManager instance = new WorldManager(); @@ -39,17 +35,16 @@ public class WorldManager { public Database chainDB = new Database("blockchain"); public Database stateDB = new Database("state"); - public Trie allAccountsState = new Trie(stateDB.getDb()); + public Trie worldState = new Trie(stateDB.getDb()); + public void applyTransaction(Transaction tx) { - public void applyTransaction(Transaction tx){ - - // todo: refactor the wallet transactions to the world manager + // TODO: refactor the wallet transactions to the world manager MainData.instance.getBlockchain().addWalletTransaction(tx); // 1. VALIDATE THE NONCE byte[] senderAddress = tx.getSender(); - byte[] stateData = allAccountsState.get(senderAddress); + byte[] stateData = worldState.get(senderAddress); if (stateData == null || stateData.length == 0) { if (stateLogger.isWarnEnabled()) @@ -58,61 +53,51 @@ public class WorldManager { } AccountState senderState = new AccountState(stateData); - if (senderState.getNonce().compareTo(new BigInteger(tx.getNonce())) != 0){ - - if (stateLogger.isWarnEnabled()) - stateLogger.warn("Invalid nonce account.nonce={} tx.nonce={}", - senderState.getNonce(), - new BigInteger(tx.getNonce())); + if (senderState.getNonce().compareTo(new BigInteger(tx.getNonce())) != 0) { + if (stateLogger.isWarnEnabled()) + stateLogger.warn("Invalid nonce account.nonce={} tx.nonce={}", + senderState.getNonce(), new BigInteger(tx.getNonce())); return; } // 2. THE SIMPLE BALANCE CHANGE SHOULD HAPPEN ANYWAY - AccountState recieverState = null; + AccountState receiverState = null; // Check if the receive is a new contract - if (tx.isContractCreation()){ - - byte[] contractAddress= tx.getContractAddress(); - AccountState contractAccount = new AccountState(BigInteger.ZERO, BigInteger.valueOf(0)); - allAccountsState.update(contractAddress, contractAccount.getEncoded()); - recieverState = contractAccount; + if (tx.isContractCreation()) { + byte[] contractAddress = tx.getContractAddress(); + receiverState = new AccountState(); + worldState.update(contractAddress, receiverState.getEncoded()); stateLogger.info("New contract created address={}", Hex.toHexString(contractAddress)); - } - - // if reciver was not set by - // creation of contract - if (recieverState == null) { - byte[] accountData = this.allAccountsState.get(tx.getReceiveAddress()); + } else { + // receiver was not set by creation of contract + byte[] accountData = this.worldState.get(tx.getReceiveAddress()); if (accountData.length == 0){ - - recieverState = new AccountState(tx.getKey()); + receiverState = new AccountState(); if (stateLogger.isInfoEnabled()) stateLogger.info("New account created address={}", Hex.toHexString(tx.getReceiveAddress())); } else { - recieverState = new AccountState(accountData); + receiverState = new AccountState(accountData); if (stateLogger.isInfoEnabled()) stateLogger.info("Account updated address={}", Hex.toHexString(tx.getReceiveAddress())); } } - - recieverState.addToBalance(new BigInteger(1, tx.getValue())); - senderState.addToBalance(new BigInteger(1, tx.getValue()).negate()); - - if (senderState.getBalance().compareTo(BigInteger.ZERO) == 1){ - - senderState.incrementNonce(); - allAccountsState.update(tx.getSender(), senderState.getEncoded()); - allAccountsState.update(tx.getReceiveAddress(), recieverState.getEncoded()); + if(tx.getValue() != null) { + receiverState.addToBalance(new BigInteger(1, tx.getValue())); + senderState.addToBalance(new BigInteger(1, tx.getValue()).negate()); } - + if (senderState.getBalance().compareTo(BigInteger.ZERO) == 1) { + senderState.incrementNonce(); + worldState.update(tx.getSender(), senderState.getEncoded()); + worldState.update(tx.getReceiveAddress(), receiverState.getEncoded()); + } // 3. FIND OUT WHAT IS THE TRANSACTION TYPE - if (tx.isContractCreation()){ + if (tx.isContractCreation()) { byte[] initCode = tx.getData(); @@ -122,7 +107,7 @@ public class WorldManager { ProgramResult result = program.getResult(); byte[] bodyCode = result.gethReturn().array(); - // todo: what if the body code is null , still submit ? + // TODO: what if the body code is null , still submit ? // TODO: (!!!!!) ALL THE CHECKS FOR THE PROGRAM RESULT @@ -133,40 +118,31 @@ public class WorldManager { stateLogger.info("saving code of the contract to the db: sha3(code)={} code={}", Hex.toHexString(key), Hex.toHexString(bodyCode)); - - } else{ - - - // todo 2. check if the address is a contract, if it is perform contract call - + } else { + // TODO: 2. check if the address is a contract, if it is perform contract call } - pendingTransactions.put(Hex.toHexString(tx.getHash()), tx); } - public void applyTransactionList(List txList){ + public void applyTransactionList(List txList) { for (Transaction tx : txList){ applyTransaction(tx); } } - public void applyBlock(Block block){ - + public void applyBlock(Block block) { List txList = block.getTransactionsList(); applyTransactionList(txList); } - public void applyBlockList(List blocks){ - for (int i = blocks.size() - 1; i >= 0 ; --i){ + public void applyBlockList(List blocks) { + for (int i = blocks.size() - 1; i >= 0 ; --i) { applyBlock(blocks.get(i)); } } - - - public void close(){ + public void close() { chainDB.close(); stateDB.close(); } - } diff --git a/ethereumj-core/src/main/java/org/ethereum/net/client/ClientPeer.java b/ethereumj-core/src/main/java/org/ethereum/net/client/ClientPeer.java index eb661f4c..6c0e1435 100644 --- a/ethereumj-core/src/main/java/org/ethereum/net/client/ClientPeer.java +++ b/ethereumj-core/src/main/java/org/ethereum/net/client/ClientPeer.java @@ -7,7 +7,6 @@ import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.nio.NioSocketChannel; import io.netty.handler.timeout.ReadTimeoutHandler; -import org.ethereum.config.SystemProperties; import org.ethereum.core.Transaction; import org.ethereum.gui.PeerListener; import org.ethereum.manager.MainData; @@ -23,7 +22,6 @@ import java.util.concurrent.TimeUnit; import static org.ethereum.config.SystemProperties.CONFIG; - /** * www.ethereumJ.com * User: Roman Mandeleil diff --git a/ethereumj-core/src/main/java/org/ethereum/net/client/EthereumProtocolHandler.java b/ethereumj-core/src/main/java/org/ethereum/net/client/EthereumProtocolHandler.java index 73c92346..8cddb662 100644 --- a/ethereumj-core/src/main/java/org/ethereum/net/client/EthereumProtocolHandler.java +++ b/ethereumj-core/src/main/java/org/ethereum/net/client/EthereumProtocolHandler.java @@ -10,7 +10,6 @@ import io.netty.channel.FixedRecvByteBufAllocator; import java.util.*; import org.ethereum.core.Block; -import org.ethereum.core.Transaction; import org.ethereum.gui.PeerListener; import org.ethereum.manager.MainData; import org.ethereum.manager.WorldManager; @@ -38,7 +37,7 @@ import org.spongycastle.util.encoders.Hex; */ public class EthereumProtocolHandler extends ChannelInboundHandlerAdapter { - Logger logger = LoggerFactory.getLogger("wire"); + Logger logger = LoggerFactory.getLogger("Wire"); Timer chainAskTimer = new Timer(); int secToAskForChain = 1; diff --git a/ethereumj-core/src/main/java/org/ethereum/net/peerdiscovery/EthereumPeerTasterHandler.java b/ethereumj-core/src/main/java/org/ethereum/net/peerdiscovery/EthereumPeerTasterHandler.java index d5e36371..03c9a8a5 100644 --- a/ethereumj-core/src/main/java/org/ethereum/net/peerdiscovery/EthereumPeerTasterHandler.java +++ b/ethereumj-core/src/main/java/org/ethereum/net/peerdiscovery/EthereumPeerTasterHandler.java @@ -5,7 +5,6 @@ import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelInboundHandlerAdapter; import io.netty.channel.ChannelOption; import io.netty.channel.FixedRecvByteBufAllocator; -import org.ethereum.crypto.HashUtil; import org.ethereum.gui.PeerListener; import org.ethereum.manager.MainData; import org.ethereum.net.Command; @@ -29,13 +28,12 @@ import static org.ethereum.net.Command.*; */ public class EthereumPeerTasterHandler extends ChannelInboundHandlerAdapter { - Logger logger = LoggerFactory.getLogger(getClass()); + Logger logger = LoggerFactory.getLogger("Wire"); Timer timer = null; private final static byte[] MAGIC_PREFIX = {(byte)0x22, (byte)0x40, (byte)0x08, (byte)0x91}; private final static byte[] HELLO_MESSAGE = StaticMessages.HELLO_MESSAGE.getPayload(); - private final static byte[] HELLO_MESSAGE_LEN = ByteUtil.calcPacketLength(HELLO_MESSAGE); private long lastPongTime = 0; private boolean tearDown = false; @@ -200,7 +198,4 @@ public class EthereumPeerTasterHandler extends ChannelInboundHandlerAdapter { buffer.writeBytes(StaticMessages.GET_PEERS); ctx.writeAndFlush(buffer); } - - - } \ No newline at end of file diff --git a/ethereumj-core/src/main/java/org/ethereum/vm/VM.java b/ethereumj-core/src/main/java/org/ethereum/vm/VM.java index b515ffbe..10ee8604 100644 --- a/ethereumj-core/src/main/java/org/ethereum/vm/VM.java +++ b/ethereumj-core/src/main/java/org/ethereum/vm/VM.java @@ -10,21 +10,47 @@ import java.nio.ByteBuffer; import static org.ethereum.vm.OpCode.PUSH1; /** - * www.ethereumJ.com - * User: Roman Mandeleil - * Created on: 01/06/2014 10:44 + * The Ethereum Virtual Machine (EVM) is responsible for initialization + * and executing a transaction on a contract. + * + * It is a quasi-Turing-complete machine; the quasi qualification + * comes from the fact that the computation is intrinsically bounded + * through a parameter, gas, which limits the total amount of computation done. + * + * The EVM is a simple stack-based architecture. The word size of the machine + * (and thus size of stack item) is 256-bit. This was chosen to facilitate + * the SHA3-256 hash scheme and elliptic-curve computations. The memory model + * is a simple word-addressed byte array. The stack has an unlimited size. + * The machine also has an independent storage model; this is similar in concept + * to the memory but rather than a byte array, it is a word-addressable word array. + * + * Unlike memory, which is volatile, storage is non volatile and is + * maintained as part of the system state. All locations in both storage + * and memory are well-defined initially as zero. + * + * The machine does not follow the standard von Neumann architecture. + * Rather than storing program code in generally-accessible memory or storage, + * it is stored separately in a virtual ROM interactable only though + * a specialised instruction. + * + * The machine can have exceptional execution for several reasons, + * including stack underflows and invalid instructions. These unambiguously + * and validly result in immediate halting of the machine with all state changes + * left intact. The one piece of exceptional execution that does not leave + * state changes intact is the out-of-gas (OOG) exception. + * + * Here, the machine halts immediately and reports the issue to + * the execution agent (either the transaction processor or, recursively, + * the spawning execution environment) and which will deal with it separately. */ - public class VM { static private BigInteger _32_ = BigInteger.valueOf(32); - Logger logger = LoggerFactory.getLogger("VM"); - + private Logger logger = LoggerFactory.getLogger(VM.class); public void step(Program program) { - try { byte op = program.getCurrentOp(); @@ -35,73 +61,63 @@ public class VM { switch (OpCode.code(op)) { case SHA3: program.spendGas(GasCost.SHA3); - break; + break; case SLOAD: program.spendGas(GasCost.SLOAD); - break; + break; case SSTORE: // todo: calc gas in the execution // todo: according to the size - break; + break; case BALANCE: program.spendGas(GasCost.BALANCE); - break; + break; case CREATE: program.spendGas(GasCost.CREATE); - break; + break; case CALL: program.spendGas(GasCost.CALL); - break; + break; case MSTORE8: case MSTORE: // todo: calc gas in the execution // todo: according to the size - break; + break; default: program.spendGas(GasCost.STEP); - break; + break; } - switch (OpCode.code(op)) { - /** * Stop and Arithmetic Operations */ - case STOP:{ program.setHReturn(ByteBuffer.allocate(0)); program.stop(); - } - break; + } break; case ADD:{ - DataWord word1 = program.stackPop(); DataWord word2 = program.stackPop(); word1.add(word2); program.stackPush(word1); program.step(); - } - break; + } break; case MUL:{ - DataWord word1 = program.stackPop(); DataWord word2 = program.stackPop(); word1.mul(word2); program.stackPush(word1); program.step(); - } - break; + } break; case SUB:{ - DataWord word1 = program.stackPop(); DataWord word2 = program.stackPop(); word1.sub(word2); program.stackPush(word1); program.step(); - } - break; + } break; case DIV:{ DataWord word1 = program.stackPop(); @@ -109,8 +125,7 @@ public class VM { word1.div(word2); program.stackPush(word1); program.step(); - } - break; + } break; case SDIV:{ DataWord word1 = program.stackPop(); @@ -118,44 +133,35 @@ public class VM { word1.sDiv(word2); program.stackPush(word1); program.step(); - } - break; + } break; case MOD:{ - DataWord word1 = program.stackPop(); DataWord word2 = program.stackPop(); word1.mod(word2); program.stackPush(word1); program.step(); - } - break; + } break; case SMOD:{ - DataWord word1 = program.stackPop(); DataWord word2 = program.stackPop(); word1.sMod(word2); program.stackPush(word1); program.step(); - } - break; + } break; case EXP:{ - DataWord word1 = program.stackPop(); DataWord word2 = program.stackPop(); word1.exp(word2); program.stackPush(word1); program.step(); - } - break; + } break; case NEG:{ DataWord word1 = program.stackPop(); word1.negate(); program.stackPush(word1); program.step(); - } - break; + } break; case LT:{ - // todo: can be improved by not using BigInteger DataWord word1 = program.stackPop(); DataWord word2 = program.stackPop(); @@ -167,10 +173,8 @@ public class VM { } program.stackPush(word1); program.step(); - } - break; + } break; case SLT:{ - // todo: can be improved by not using BigInteger DataWord word1 = program.stackPop(); DataWord word2 = program.stackPop(); @@ -182,9 +186,8 @@ public class VM { } program.stackPush(word1); program.step(); - }break; + } break; case SGT:{ - // todo: can be improved by not using BigInteger DataWord word1 = program.stackPop(); DataWord word2 = program.stackPop(); @@ -196,9 +199,8 @@ public class VM { } program.stackPush(word1); program.step(); - }break; + } break; case GT:{ - // todo: can be improved by not using BigInteger DataWord word1 = program.stackPop(); DataWord word2 = program.stackPop(); @@ -210,7 +212,7 @@ public class VM { } program.stackPush(word1); program.step(); - }break; + } break; case EQ:{ DataWord word1 = program.stackPop(); DataWord word2 = program.stackPop(); @@ -222,8 +224,7 @@ public class VM { } program.stackPush(word1); program.step(); - } - break; + } break; case NOT: { DataWord word1 = program.stackPop(); if (word1.isZero()){ @@ -233,42 +234,35 @@ public class VM { } program.stackPush(word1); program.step(); - } - break; + } break; /** * Bitwise Logic Operations */ - case AND:{ DataWord word1 = program.stackPop(); DataWord word2 = program.stackPop(); word1.and(word2); program.stackPush(word1); program.step(); - } - break; + } break; case OR: { DataWord word1 = program.stackPop(); DataWord word2 = program.stackPop(); word1.or(word2); program.stackPush(word1); program.step(); - } - break; + } break; case XOR: { DataWord word1 = program.stackPop(); DataWord word2 = program.stackPop(); word1.xor(word2); program.stackPush(word1); program.step(); - } - break; + } break; case BYTE:{ - DataWord word1 = program.stackPop(); DataWord word2 = program.stackPop(); - DataWord result = null; if (word1.value().compareTo(_32_) == -1){ byte tmp = word2.getData()[word1.value().intValue()]; @@ -280,13 +274,11 @@ public class VM { } program.stackPush(result); program.step(); - } - break; + } break; /** * SHA3 */ - case SHA3:{ DataWord memOffsetData = program.stackPop(); DataWord lengthData = program.stackPop(); @@ -297,60 +289,50 @@ public class VM { program.stackPush(word); program.step(); - } - break; + } break; /** * Environmental Information */ - case ADDRESS:{ DataWord address = program.getOwnerAddress(); program.stackPush(address); program.step(); - } - break; + } break; case BALANCE:{ DataWord balance = program.getBalance(); program.stackPush(balance); program.step(); - } - break; + } break; case ORIGIN:{ DataWord originAddress = program.getOriginAddress(); program.stackPush(originAddress); program.step(); - } - break; + } break; case CALLER:{ DataWord callerAddress = program.getCallerAddress(); program.stackPush(callerAddress); program.step(); - } - break; + } break; case CALLVALUE:{ DataWord callValue = program.getCallValue(); program.stackPush(callValue); program.step(); - } - break; + } break; case CALLDATALOAD:{ DataWord dataOffs = program.stackPop(); DataWord value = program.getDataValue(dataOffs); program.stackPush(value); program.step(); - } - break; + } break; case CALLDATASIZE:{ DataWord dataSize = program.getDataSize(); program.stackPush(dataSize); program.step(); - } - break; + } break; case CALLDATACOPY:{ - DataWord memOffsetData = program.stackPop(); DataWord dataOffsetData = program.stackPop(); DataWord lengthData = program.stackPop(); @@ -358,15 +340,12 @@ public class VM { byte[] msgData = program.getDataCopy(dataOffsetData, lengthData); program.memorySave(memOffsetData.data, msgData); program.step(); - - } break; + } break; case CODESIZE:{ - DataWord length = new DataWord(program.ops.length); program.stackPush(length); program.step(); - } - break; + } break; case CODECOPY:{ DataWord memOffsetData = program.stackPop(); DataWord codeOffsetData = program.stackPop(); @@ -377,7 +356,6 @@ public class VM { int memOffset = memOffsetData.value().intValue(); if (program.ops.length < length + codeOffset){ - program.stop(); break; } @@ -387,8 +365,7 @@ public class VM { program.memorySave(memOffsetData.getData(), code); program.step(); - } - break; + } break; case GASPRICE: break; @@ -408,52 +385,43 @@ public class VM { break; case GASLIMIT: break; - - case POP:{ program.stackPop(); program.step(); - } - break; + } break; case DUP:{ DataWord word_1 = program.stackPop(); DataWord word_2 = word_1.clone(); program.stackPush(word_1); program.stackPush(word_2); program.step(); - } - break; + } break; case SWAP:{ DataWord word_1 = program.stackPop(); DataWord word_2 = program.stackPop(); program.stackPush(word_1); program.stackPush(word_2); program.step(); - } - break; + } break; case MLOAD:{ DataWord addr = program.stackPop(); DataWord data = program.memoryLoad(addr); program.stackPush(data); program.step(); - } - break; + } break; case MSTORE:{ DataWord addr = program.stackPop(); DataWord value = program.stackPop(); program.memorySave(addr, value); program.step(); - } - break; + } break; case MSTORE8:{ - DataWord addr = program.stackPop(); DataWord value = program.stackPop(); byte[] byteVal = {value.getData()[31]}; program.memorySave(addr.getData(), byteVal); program.step(); - } - break; + } break; case SLOAD:{ DataWord key = program.stackPop(); DataWord val = program.storageLoad(key); @@ -462,8 +430,7 @@ public class VM { } program.stackPush(val); program.step(); - } - break; + } break; case SSTORE:{ DataWord addr = program.stackPop(); DataWord value = program.stackPop(); @@ -477,15 +444,12 @@ public class VM { program.spendGas(GasCost.SSTORE * 0); } else program.spendGas(GasCost.SSTORE); - program.step(); - } - break; + } break; case JUMP:{ DataWord pos = program.stackPop(); program.setPC(pos); - } - break; + } break; case JUMPI:{ DataWord pos = program.stackPop(); DataWord cond = program.stackPop(); @@ -495,23 +459,19 @@ public class VM { } else{ program.step(); } - } - break; + } break; case PC:{ int pc = program.getPC(); DataWord pcWord = new DataWord(pc); program.stackPush(pcWord); program.step(); - } - break; + } break; case MSIZE:{ - int memSize = program.getMemSize(); DataWord wordMemSize = new DataWord(memSize); program.stackPush(wordMemSize); program.step(); - } - break; + } break; case GAS: break; @@ -519,14 +479,12 @@ public class VM { case PUSH9: case PUSH10: case PUSH11: case PUSH12: case PUSH13: case PUSH14: case PUSH15: case PUSH16: case PUSH17: case PUSH18: case PUSH19: case PUSH20: case PUSH21: case PUSH22: case PUSH23: case PUSH24: case PUSH25: case PUSH26: case PUSH27: case PUSH28: case PUSH29: case PUSH30: case PUSH31: case PUSH32:{ - program.step(); int nPush = op - PUSH1.val() + 1; byte[] data = program.sweep(nPush); program.stackPush(data); - } - break; + } break; case CREATE:{ DataWord gas = program.stackPop(); DataWord inOffset = program.stackPop(); @@ -535,8 +493,7 @@ public class VM { // todo: implement contract creation program.step(); - } - break; + } break; case CALL:{ DataWord gas = program.stackPop(); DataWord toAddress = program.stackPop(); @@ -548,10 +505,8 @@ public class VM { // todo: the contract for real program.step(); - } - break; + } break; case RETURN:{ - DataWord offset = program.stackPop(); DataWord size = program.stackPop(); @@ -560,14 +515,12 @@ public class VM { program.step(); program.stop(); - } - break; + } break; case SUICIDE:{ DataWord address = program.stackPop(); // todo: transfer left balance to the address program.stop(); - } - break; + } break; default:{ } @@ -583,15 +536,12 @@ public class VM { } - - public void play(Program program){ + public void play(Program program) { try { while(!program.isStopped()) this.step(program); } catch (RuntimeException e) { program.setRuntimeFailure(e); } - } - } diff --git a/ethereumj-core/src/test/java/org/ethereum/core/WalletTest.java b/ethereumj-core/src/test/java/org/ethereum/core/WalletTest.java index b926261f..7ce346fb 100644 --- a/ethereumj-core/src/test/java/org/ethereum/core/WalletTest.java +++ b/ethereumj-core/src/test/java/org/ethereum/core/WalletTest.java @@ -29,8 +29,8 @@ public class WalletTest { wallet.importKey(catKey.getPrivKeyBytes()); - AccountState cowAddressState = (AccountState) wallet.getAddressState(cowKey.getAddress()); - AccountState catAddressState = (AccountState) wallet.getAddressState(catKey.getAddress()); + AccountState cowAddressState = wallet.getAccountState(cowKey.getAddress()); + AccountState catAddressState = wallet.getAccountState(catKey.getAddress()); cowAddressState.addToBalance(new BigInteger("234234")); catAddressState.addToBalance(new BigInteger("84758"));