Merge pull request #27 from nicksavers/master
Refactoring and cleanup with documentation
This commit is contained in:
commit
037e1f230c
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@ 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("Chain");
|
||||
|
||||
// to avoid using minGasPrice=0 from Genesis for the wallet
|
||||
private static long INITIAL_MIN_GAS_PRICE = 10 * SZABO.longValue();
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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<Address, BigInteger> rows = new HashMap<>();
|
||||
|
||||
// <address, info> table for a wallet
|
||||
private HashMap<String, AccountState> rows = new HashMap<String, AccountState>();
|
||||
private HashMap<String, Account> rows = new HashMap<String, Account>();
|
||||
private long high;
|
||||
|
||||
private List<WalletListener> listeners = new ArrayList<WalletListener>();
|
||||
|
||||
private HashMap<BigInteger, Transaction> transactionMap = new HashMap<BigInteger, Transaction>();
|
||||
|
||||
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<AccountState> getAddressStateCollection(){
|
||||
public Collection<Account> 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);
|
||||
|
|
|
@ -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<AddressStateWraper> creatorAddressCombo;
|
||||
JComboBox<AccountWrapper> creatorAddressCombo;
|
||||
final JTextField gasInput;
|
||||
final JTextField contractAddrInput;
|
||||
JTextArea msgDataTA;
|
||||
|
@ -116,7 +116,7 @@ class ContractCallDialog extends JDialog implements MessageAwareDialog{
|
|||
|
||||
gasInput.setText("1000");
|
||||
|
||||
JComboBox<AddressStateWraper> creatorAddressCombo = new JComboBox<AddressStateWraper>() {
|
||||
JComboBox<AccountWrapper> creatorAddressCombo = new JComboBox<AccountWrapper>() {
|
||||
@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<AccountState> addressStates =
|
||||
MainData.instance.getWallet().getAddressStateCollection();
|
||||
Collection<Account> 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;
|
||||
|
|
|
@ -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<AddressStateWraper> creatorAddressCombo;
|
||||
JComboBox<AccountWrapper> creatorAddressCombo;
|
||||
final JTextField gasInput;
|
||||
final JTextField contractAddrInput;
|
||||
|
||||
|
@ -139,7 +140,7 @@ class ContractSubmitDialog extends JDialog implements MessageAwareDialog {
|
|||
|
||||
gasInput.setText("1000");
|
||||
|
||||
JComboBox<AddressStateWraper> creatorAddressCombo = new JComboBox<AddressStateWraper>(){
|
||||
JComboBox<AccountWrapper> creatorAddressCombo = new JComboBox<AccountWrapper>(){
|
||||
@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<AccountState> addressStates =
|
||||
MainData.instance.getWallet().getAddressStateCollection();
|
||||
Collection<Account> 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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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()));
|
||||
|
||||
|
|
|
@ -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<Transaction> txList){
|
||||
public void applyTransactionList(List<Transaction> txList) {
|
||||
for (Transaction tx : txList){
|
||||
applyTransaction(tx);
|
||||
}
|
||||
}
|
||||
|
||||
public void applyBlock(Block block){
|
||||
|
||||
public void applyBlock(Block block) {
|
||||
List<Transaction> txList = block.getTransactionsList();
|
||||
applyTransactionList(txList);
|
||||
}
|
||||
|
||||
public void applyBlockList(List<Block> blocks){
|
||||
for (int i = blocks.size() - 1; i >= 0 ; --i){
|
||||
public void applyBlockList(List<Block> blocks) {
|
||||
for (int i = blocks.size() - 1; i >= 0 ; --i) {
|
||||
applyBlock(blocks.get(i));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void close(){
|
||||
public void close() {
|
||||
chainDB.close();
|
||||
stateDB.close();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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"));
|
||||
|
|
Loading…
Reference in New Issue