parent
b2ac8fc47b
commit
41efe75aec
|
@ -2,8 +2,11 @@ package org.ethereum.core;
|
||||||
|
|
||||||
import static org.ethereum.util.ByteUtil.EMPTY_BYTE_ARRAY;
|
import static org.ethereum.util.ByteUtil.EMPTY_BYTE_ARRAY;
|
||||||
import static org.ethereum.crypto.HashUtil.EMPTY_DATA_HASH;
|
import static org.ethereum.crypto.HashUtil.EMPTY_DATA_HASH;
|
||||||
|
|
||||||
import org.ethereum.util.RLP;
|
import org.ethereum.util.RLP;
|
||||||
import org.ethereum.util.RLPList;
|
import org.ethereum.util.RLPList;
|
||||||
|
import org.spongycastle.util.Arrays;
|
||||||
|
import org.spongycastle.util.encoders.Hex;
|
||||||
|
|
||||||
import java.math.BigInteger;
|
import java.math.BigInteger;
|
||||||
|
|
||||||
|
@ -113,4 +116,16 @@ public class AccountState {
|
||||||
}
|
}
|
||||||
return rlpEncoded;
|
return rlpEncoded;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String toString() {
|
||||||
|
String ret = "Nonce: " + this.getNonce().toString() + "\n" +
|
||||||
|
"Balance: " + Denomination.toFriendlyString(getBalance()) + "\n";
|
||||||
|
|
||||||
|
if(this.getStateRoot()!= null && !Arrays.areEqual(this.getStateRoot(), EMPTY_BYTE_ARRAY))
|
||||||
|
ret += "State Root: " + Hex.toHexString(this.getStateRoot()) + "\n";
|
||||||
|
if(this.getCodeHash() != null && !Arrays.areEqual(this.getCodeHash(), EMPTY_DATA_HASH))
|
||||||
|
ret += "Code Hash: " + Hex.toHexString(this.getCodeHash());
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,4 +31,33 @@ public enum Denomination {
|
||||||
private static BigInteger newBigInt(int value) {
|
private static BigInteger newBigInt(int value) {
|
||||||
return BigInteger.valueOf(10).pow(value);
|
return BigInteger.valueOf(10).pow(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static String toFriendlyString(BigInteger value) {
|
||||||
|
if(value.compareTo(DOUGLAS.value()) == 1 || value.compareTo(DOUGLAS.value()) == 0) {
|
||||||
|
return Float.toString(value.divide(DOUGLAS.value()).floatValue()) + " DOUGLAS";
|
||||||
|
}
|
||||||
|
else if(value.compareTo(EINSTEIN.value()) == 1 || value.compareTo(EINSTEIN.value()) == 0) {
|
||||||
|
return Float.toString(value.divide(EINSTEIN.value()).floatValue()) + " EINSTEIN";
|
||||||
|
}
|
||||||
|
else if(value.compareTo(ETHER.value()) == 1 || value.compareTo(ETHER.value()) == 0) {
|
||||||
|
return Float.toString(value.divide(ETHER.value()).floatValue()) + " ETHER";
|
||||||
|
}
|
||||||
|
else if(value.compareTo(FINNY.value()) == 1 || value.compareTo(FINNY.value()) == 0) {
|
||||||
|
return Float.toString(value.divide(FINNY.value()).floatValue()) + " FINNY";
|
||||||
|
}
|
||||||
|
else if(value.compareTo(SZABO.value()) == 1 || value.compareTo(SZABO.value()) == 0) {
|
||||||
|
return Float.toString(value.divide(SZABO.value()).floatValue()) + " SZABO";
|
||||||
|
}
|
||||||
|
else if(value.compareTo(SHANNON.value()) == 1 || value.compareTo(SHANNON.value()) == 0) {
|
||||||
|
return Float.toString(value.divide(SHANNON.value()).floatValue()) + " SHANNON";
|
||||||
|
}
|
||||||
|
else if(value.compareTo(BABBAGE.value()) == 1 || value.compareTo(BABBAGE.value()) == 0) {
|
||||||
|
return Float.toString(value.divide(BABBAGE.value()).floatValue()) + " BABBAGE";
|
||||||
|
}
|
||||||
|
else if(value.compareTo(ADA.value()) == 1 || value.compareTo(ADA.value()) == 0) {
|
||||||
|
return Float.toString(value.divide(ADA.value()).floatValue()) + " ADA";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return Float.toString(value.divide(WEI.value()).floatValue()) + " WEI";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -75,10 +75,14 @@ public class RepositoryImpl implements Repository {
|
||||||
* @See loadBlockchain() to update the stateRoot
|
* @See loadBlockchain() to update the stateRoot
|
||||||
*/
|
*/
|
||||||
public RepositoryImpl() {
|
public RepositoryImpl() {
|
||||||
chainDB = new DatabaseImpl("blockchain");
|
this("blockchain", "details", "state");
|
||||||
detailsDB = new DatabaseImpl("details");
|
}
|
||||||
|
|
||||||
|
public RepositoryImpl(String blockChainDbName, String detailsDbName, String stateDbName) {
|
||||||
|
chainDB = new DatabaseImpl(blockChainDbName);
|
||||||
|
detailsDB = new DatabaseImpl(detailsDbName);
|
||||||
contractDetailsDB = new TrackDatabase(detailsDB);
|
contractDetailsDB = new TrackDatabase(detailsDB);
|
||||||
stateDB = new DatabaseImpl("state");
|
stateDB = new DatabaseImpl(stateDbName);
|
||||||
worldState = new Trie(stateDB.getDb());
|
worldState = new Trie(stateDB.getDb());
|
||||||
accountStateDB = new TrackTrie(worldState);
|
accountStateDB = new TrackTrie(worldState);
|
||||||
}
|
}
|
||||||
|
@ -479,6 +483,9 @@ public class RepositoryImpl implements Repository {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public DBIterator getContractDetailsDBIterator() {
|
||||||
|
return detailsDB.iterator();
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isClosed(){
|
public boolean isClosed(){
|
||||||
return chainDB == null;
|
return chainDB == null;
|
||||||
|
|
|
@ -695,6 +695,37 @@ public class Program {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static String stringify(byte[] code, int index, String result) {
|
||||||
|
if(code == null || code.length == 0)
|
||||||
|
return result;
|
||||||
|
|
||||||
|
OpCode op = OpCode.code(code[index]);
|
||||||
|
byte[] continuedCode = null;
|
||||||
|
|
||||||
|
switch(op){
|
||||||
|
case PUSH1: case PUSH2: case PUSH3: case PUSH4: case PUSH5: case PUSH6: case PUSH7: case PUSH8:
|
||||||
|
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:
|
||||||
|
result += ' ' + op.name() + ' ';
|
||||||
|
|
||||||
|
int nPush = op.val() - OpCode.PUSH1.val() + 1;
|
||||||
|
byte[] data = Arrays.copyOfRange(code, index+1, index + nPush + 1);
|
||||||
|
result += new BigInteger(data).toString() + ' ';
|
||||||
|
|
||||||
|
continuedCode = Arrays.copyOfRange(code, index + nPush + 1, code.length);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
result += ' ' + op.name();
|
||||||
|
continuedCode = Arrays.copyOfRange(code, index + 1, code.length);
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return stringify(continuedCode, 0, result);
|
||||||
|
}
|
||||||
|
|
||||||
public void addListener(ProgramListener listener) {
|
public void addListener(ProgramListener listener) {
|
||||||
this.listener = listener;
|
this.listener = listener;
|
||||||
|
|
|
@ -24,7 +24,7 @@ public class ProgramInvokeMockImpl implements ProgramInvoke {
|
||||||
}
|
}
|
||||||
|
|
||||||
public ProgramInvokeMockImpl() {
|
public ProgramInvokeMockImpl() {
|
||||||
this.repository = new RepositoryImpl();
|
this.repository = new RepositoryImpl("blockchainMoc", "detailsMoc", "stateMoc");
|
||||||
this.repository.createAccount(Hex.decode(ownerAddress));
|
this.repository.createAccount(Hex.decode(ownerAddress));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,135 @@
|
||||||
|
package org.ethereum.gui;
|
||||||
|
|
||||||
|
import java.awt.BorderLayout;
|
||||||
|
import java.awt.Dimension;
|
||||||
|
import java.awt.Image;
|
||||||
|
import java.awt.Toolkit;
|
||||||
|
import java.math.BigInteger;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import javax.swing.JFrame;
|
||||||
|
import javax.swing.JPanel;
|
||||||
|
import javax.swing.JScrollPane;
|
||||||
|
import javax.swing.JTable;
|
||||||
|
import javax.swing.table.AbstractTableModel;
|
||||||
|
|
||||||
|
import org.ethereum.core.Account;
|
||||||
|
import org.ethereum.core.AccountState;
|
||||||
|
import org.ethereum.core.Denomination;
|
||||||
|
import org.ethereum.crypto.HashUtil;
|
||||||
|
import org.ethereum.manager.WorldManager;
|
||||||
|
import org.iq80.leveldb.DBIterator;
|
||||||
|
import org.spongycastle.util.Arrays;
|
||||||
|
import org.spongycastle.util.encoders.Hex;
|
||||||
|
|
||||||
|
public class AccountsListWindow extends JFrame {
|
||||||
|
|
||||||
|
private JTable tblAccountsDataTable;
|
||||||
|
private AccountsDataAdapter adapter;
|
||||||
|
|
||||||
|
public AccountsListWindow() {
|
||||||
|
java.net.URL url = ClassLoader.getSystemResource("ethereum-icon.png");
|
||||||
|
Toolkit kit = Toolkit.getDefaultToolkit();
|
||||||
|
Image img = kit.createImage(url);
|
||||||
|
this.setIconImage(img);
|
||||||
|
setTitle("Accounts List");
|
||||||
|
setSize(700, 500);
|
||||||
|
setLocation(50, 180);
|
||||||
|
setResizable(false);
|
||||||
|
|
||||||
|
JPanel panel = new JPanel();
|
||||||
|
getContentPane().add(panel);
|
||||||
|
|
||||||
|
tblAccountsDataTable = new JTable();
|
||||||
|
|
||||||
|
adapter = new AccountsDataAdapter(new ArrayList<DataClass>());
|
||||||
|
tblAccountsDataTable.setModel(adapter);
|
||||||
|
|
||||||
|
JScrollPane scrollPane = new JScrollPane(tblAccountsDataTable);
|
||||||
|
scrollPane.setPreferredSize(new Dimension(680,490));
|
||||||
|
panel.add(scrollPane);
|
||||||
|
|
||||||
|
loadAccounts();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void loadAccounts() {
|
||||||
|
new Thread(){
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run(){
|
||||||
|
DBIterator i = WorldManager.getInstance().getRepository().getContractDetailsDBIterator();
|
||||||
|
while(i.hasNext()) {
|
||||||
|
DataClass dc = new DataClass();
|
||||||
|
dc.address = i.next().getKey();
|
||||||
|
|
||||||
|
AccountState state = WorldManager.getInstance().getRepository().getAccountState(dc.address);
|
||||||
|
dc.accountState = state;
|
||||||
|
|
||||||
|
adapter.addDataPiece(dc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
private class AccountsDataAdapter extends AbstractTableModel {
|
||||||
|
List<DataClass> data;
|
||||||
|
|
||||||
|
final String[] columns = new String[]{ "Account", "Balance", "Is Contract"};
|
||||||
|
|
||||||
|
public AccountsDataAdapter(List<DataClass> data) {
|
||||||
|
this.data = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addDataPiece(DataClass d) {
|
||||||
|
data.add(d);
|
||||||
|
this.fireTableRowsInserted(Math.min(data.size() - 2, 0), data.size() - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getRowCount() {
|
||||||
|
return data.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getColumnCount() {
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getColumnName(int column) {
|
||||||
|
return columns[column];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isCellEditable(int row, int column) { // custom isCellEditable function
|
||||||
|
return column == 0? true:false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object getValueAt(int rowIndex, int columnIndex) {
|
||||||
|
if(columnIndex == 0) {
|
||||||
|
return Hex.toHexString(data.get(rowIndex).address);
|
||||||
|
}
|
||||||
|
else if(columnIndex == 1 ){
|
||||||
|
if(data.get(rowIndex).accountState != null) {
|
||||||
|
return Denomination.toFriendlyString(data.get(rowIndex).accountState.getBalance());
|
||||||
|
}
|
||||||
|
return "---";
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if(data.get(rowIndex).accountState != null) {
|
||||||
|
if(!Arrays.areEqual(data.get(rowIndex).accountState.getCodeHash(), HashUtil.EMPTY_DATA_HASH))
|
||||||
|
return "Yes";
|
||||||
|
}
|
||||||
|
return "No";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class DataClass {
|
||||||
|
public byte[] address;
|
||||||
|
public AccountState accountState;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
57
ethereumj-studio/src/main/java/org/ethereum/gui/ProgramPlayDialog.java
Normal file → Executable file
57
ethereumj-studio/src/main/java/org/ethereum/gui/ProgramPlayDialog.java
Normal file → Executable file
|
@ -3,6 +3,7 @@ package org.ethereum.gui;
|
||||||
import org.ethereum.core.Block;
|
import org.ethereum.core.Block;
|
||||||
import org.ethereum.core.Transaction;
|
import org.ethereum.core.Transaction;
|
||||||
import org.ethereum.db.RepositoryImpl;
|
import org.ethereum.db.RepositoryImpl;
|
||||||
|
import org.ethereum.facade.Repository;
|
||||||
import org.ethereum.manager.WorldManager;
|
import org.ethereum.manager.WorldManager;
|
||||||
import org.ethereum.vm.*;
|
import org.ethereum.vm.*;
|
||||||
import org.spongycastle.util.encoders.Hex;
|
import org.spongycastle.util.encoders.Hex;
|
||||||
|
@ -10,6 +11,7 @@ import org.spongycastle.util.encoders.Hex;
|
||||||
import javax.swing.*;
|
import javax.swing.*;
|
||||||
import javax.swing.event.ChangeEvent;
|
import javax.swing.event.ChangeEvent;
|
||||||
import javax.swing.event.ChangeListener;
|
import javax.swing.event.ChangeListener;
|
||||||
|
|
||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
import java.awt.event.ActionEvent;
|
import java.awt.event.ActionEvent;
|
||||||
import java.awt.event.ActionListener;
|
import java.awt.event.ActionListener;
|
||||||
|
@ -28,42 +30,40 @@ public class ProgramPlayDialog extends JPanel implements ActionListener,
|
||||||
private List<String> outputList;
|
private List<String> outputList;
|
||||||
private JTextArea console;
|
private JTextArea console;
|
||||||
private JSlider stepSlider;
|
private JSlider stepSlider;
|
||||||
|
|
||||||
|
private ProgramInvoke pi;
|
||||||
|
|
||||||
public ProgramPlayDialog(byte[] code) {
|
public ProgramPlayDialog(byte[] code) {
|
||||||
|
this(code, new ProgramInvokeMockImpl(), null);
|
||||||
outputList = new ArrayList<String>();
|
|
||||||
VM vm = new VM();
|
|
||||||
|
|
||||||
ProgramInvoke pi = new ProgramInvokeMockImpl();
|
|
||||||
Program program = new Program(code, pi);
|
|
||||||
|
|
||||||
program.addListener(this);
|
|
||||||
program.fullTrace();
|
|
||||||
vm.play(program);
|
|
||||||
|
|
||||||
doGUI();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public ProgramPlayDialog(byte[] code, Transaction tx, Block lastBlock) {
|
public ProgramPlayDialog(byte[] code, Transaction tx, Block lastBlock) {
|
||||||
|
this(code,
|
||||||
outputList = new ArrayList<String>();
|
ProgramInvokeFactory.createProgramInvoke(tx,
|
||||||
|
lastBlock,
|
||||||
|
WorldManager.getInstance().getRepository()),
|
||||||
|
WorldManager.getInstance().getRepository());
|
||||||
|
}
|
||||||
|
|
||||||
|
public ProgramPlayDialog(byte[] code, ProgramInvoke programInvoke, RepositoryImpl tractRepository) {
|
||||||
|
pi = programInvoke;
|
||||||
|
|
||||||
|
outputList = new ArrayList<String>();
|
||||||
VM vm = new VM();
|
VM vm = new VM();
|
||||||
|
|
||||||
RepositoryImpl tractRepository = WorldManager.getInstance().getRepository().getTrack();
|
Program program = new Program(code, programInvoke);
|
||||||
|
|
||||||
Program program = new Program(code ,
|
|
||||||
ProgramInvokeFactory.createProgramInvoke(tx, lastBlock, tractRepository));
|
|
||||||
|
|
||||||
program.addListener(this);
|
program.addListener(this);
|
||||||
program.fullTrace();
|
program.fullTrace();
|
||||||
vm.play(program);
|
vm.play(program);
|
||||||
|
|
||||||
tractRepository.rollback();
|
if(tractRepository != null)
|
||||||
|
tractRepository.rollback();
|
||||||
|
|
||||||
doGUI();
|
doGUI();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void doGUI() {
|
public void doGUI() {
|
||||||
|
|
||||||
setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS));
|
setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS));
|
||||||
|
|
||||||
//Create the slider.
|
//Create the slider.
|
||||||
|
@ -136,7 +136,7 @@ public class ProgramPlayDialog extends JPanel implements ActionListener,
|
||||||
*/
|
*/
|
||||||
public static void createAndShowGUI(byte[] runCode, Transaction tx, Block lastBlock) {
|
public static void createAndShowGUI(byte[] runCode, Transaction tx, Block lastBlock) {
|
||||||
|
|
||||||
ProgramPlayDialog ppd;
|
final ProgramPlayDialog ppd;
|
||||||
if (tx != null)
|
if (tx != null)
|
||||||
ppd = new ProgramPlayDialog(runCode, tx, lastBlock);
|
ppd = new ProgramPlayDialog(runCode, tx, lastBlock);
|
||||||
else{
|
else{
|
||||||
|
@ -157,12 +157,21 @@ public class ProgramPlayDialog extends JPanel implements ActionListener,
|
||||||
|
|
||||||
//Add content to the window.
|
//Add content to the window.
|
||||||
frame.add(ppd, BorderLayout.CENTER);
|
frame.add(ppd, BorderLayout.CENTER);
|
||||||
|
|
||||||
|
// close event
|
||||||
|
frame.addWindowListener(new java.awt.event.WindowAdapter() {
|
||||||
|
@Override
|
||||||
|
public void windowClosing(java.awt.event.WindowEvent windowEvent) {
|
||||||
|
ppd.pi.getRepository().close();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
//Display the window.
|
//Display the window.
|
||||||
frame.pack();
|
frame.pack();
|
||||||
frame.setVisible(true);
|
frame.setVisible(true);
|
||||||
ppd.setFocus();
|
ppd.setFocus();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void output(String out) {
|
public void output(String out) {
|
||||||
|
|
|
@ -0,0 +1,353 @@
|
||||||
|
package org.ethereum.gui;
|
||||||
|
|
||||||
|
import java.awt.Color;
|
||||||
|
import java.awt.Cursor;
|
||||||
|
import java.awt.Dimension;
|
||||||
|
import java.awt.Image;
|
||||||
|
import java.awt.TextArea;
|
||||||
|
import java.awt.Toolkit;
|
||||||
|
|
||||||
|
import javax.swing.JFrame;
|
||||||
|
import javax.swing.JPanel;
|
||||||
|
|
||||||
|
import java.awt.BorderLayout;
|
||||||
|
import java.awt.event.ActionEvent;
|
||||||
|
import java.awt.event.ActionListener;
|
||||||
|
import java.awt.event.FocusEvent;
|
||||||
|
import java.awt.event.FocusListener;
|
||||||
|
import java.awt.event.ItemEvent;
|
||||||
|
import java.awt.event.ItemListener;
|
||||||
|
import java.awt.event.KeyAdapter;
|
||||||
|
import java.awt.event.KeyEvent;
|
||||||
|
import java.awt.event.MouseAdapter;
|
||||||
|
import java.awt.event.MouseEvent;
|
||||||
|
import java.awt.event.MouseListener;
|
||||||
|
import java.math.BigInteger;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import javax.swing.Box;
|
||||||
|
import javax.swing.ImageIcon;
|
||||||
|
import javax.swing.JComboBox;
|
||||||
|
import javax.swing.JLabel;
|
||||||
|
import javax.swing.JScrollPane;
|
||||||
|
import javax.swing.JTable;
|
||||||
|
import javax.swing.JTextField;
|
||||||
|
import javax.swing.JButton;
|
||||||
|
import javax.swing.JToggleButton;
|
||||||
|
import javax.swing.SwingUtilities;
|
||||||
|
import javax.swing.table.AbstractTableModel;
|
||||||
|
|
||||||
|
import org.ethereum.core.AccountState;
|
||||||
|
import org.ethereum.core.Block;
|
||||||
|
import org.ethereum.core.Transaction;
|
||||||
|
import org.ethereum.db.ContractDetails;
|
||||||
|
import org.ethereum.manager.WorldManager;
|
||||||
|
import org.ethereum.vm.DataWord;
|
||||||
|
import org.ethereum.vm.OpCode;
|
||||||
|
import org.ethereum.vm.Program;
|
||||||
|
import org.ethereum.vm.ProgramInvoke;
|
||||||
|
import org.ethereum.vm.ProgramInvokeFactory;
|
||||||
|
import org.ethereum.vm.Program.ProgramListener;
|
||||||
|
import org.spongycastle.util.encoders.DecoderException;
|
||||||
|
import org.spongycastle.util.encoders.Hex;
|
||||||
|
import java.awt.Component;
|
||||||
|
import java.awt.FlowLayout;
|
||||||
|
|
||||||
|
public class StateExplorerWindow extends JFrame{
|
||||||
|
|
||||||
|
private ToolBar toolBar = null;
|
||||||
|
private JTextField txfAccountAddress;
|
||||||
|
private WindowTextArea txaPrinter;
|
||||||
|
private JButton btnPlayCode;
|
||||||
|
private AccountsListWindow accountsListWindow;
|
||||||
|
ProgramPlayDialog codePanel;
|
||||||
|
|
||||||
|
private JTable tblStateDataTable;
|
||||||
|
private StateDataTableModel dataModel;
|
||||||
|
String[] dataTypes = {"String", "Hex", "Number"};
|
||||||
|
|
||||||
|
public StateExplorerWindow(ToolBar toolBar) {
|
||||||
|
this.toolBar = toolBar;
|
||||||
|
|
||||||
|
java.net.URL url = ClassLoader.getSystemResource("ethereum-icon.png");
|
||||||
|
Toolkit kit = Toolkit.getDefaultToolkit();
|
||||||
|
Image img = kit.createImage(url);
|
||||||
|
this.setIconImage(img);
|
||||||
|
setTitle("State Explorer");
|
||||||
|
setSize(700, 530);
|
||||||
|
setLocation(50, 180);
|
||||||
|
setResizable(false);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* top search panel
|
||||||
|
*/
|
||||||
|
JPanel panel = new JPanel();
|
||||||
|
getContentPane().add(panel);
|
||||||
|
|
||||||
|
Box horizontalBox = Box.createHorizontalBox();
|
||||||
|
panel.add(horizontalBox);
|
||||||
|
|
||||||
|
java.net.URL imageURL = ClassLoader.getSystemResource("buttons/list.png");
|
||||||
|
ImageIcon image = new ImageIcon(imageURL);
|
||||||
|
JToggleButton btnListAccounts = new JToggleButton("");
|
||||||
|
btnListAccounts.setIcon(image);
|
||||||
|
btnListAccounts.setContentAreaFilled(true);
|
||||||
|
btnListAccounts.setToolTipText("Serpent Editor");
|
||||||
|
btnListAccounts.setBackground(Color.WHITE);
|
||||||
|
btnListAccounts.setBorderPainted(false);
|
||||||
|
btnListAccounts.setFocusPainted(false);
|
||||||
|
btnListAccounts.setCursor(new Cursor(Cursor.HAND_CURSOR));
|
||||||
|
btnListAccounts.addItemListener(new ItemListener() {
|
||||||
|
@Override
|
||||||
|
public void itemStateChanged(ItemEvent e) {
|
||||||
|
SwingUtilities.invokeLater(new Runnable() {
|
||||||
|
public void run() {
|
||||||
|
if(accountsListWindow == null)
|
||||||
|
accountsListWindow = new AccountsListWindow();
|
||||||
|
accountsListWindow.setVisible(true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
horizontalBox.add(btnListAccounts);
|
||||||
|
|
||||||
|
|
||||||
|
txfAccountAddress = new JTextField();
|
||||||
|
horizontalBox.add(txfAccountAddress);
|
||||||
|
txfAccountAddress.setColumns(30);
|
||||||
|
|
||||||
|
JButton btnSearch = new JButton("Search");
|
||||||
|
horizontalBox.add(btnSearch);
|
||||||
|
btnSearch.addMouseListener(new MouseAdapter(){
|
||||||
|
@Override
|
||||||
|
public void mouseClicked(MouseEvent e) {
|
||||||
|
searchAccount(txfAccountAddress.getText());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
btnPlayCode = new JButton("Play Code");
|
||||||
|
horizontalBox.add(btnPlayCode);
|
||||||
|
btnPlayCode.addMouseListener(new MouseAdapter(){
|
||||||
|
@Override
|
||||||
|
public void mouseClicked(MouseEvent e) {
|
||||||
|
byte[] code = WorldManager.getInstance().getRepository().getCode(Hex.decode(txfAccountAddress.getText()));
|
||||||
|
if(code != null)
|
||||||
|
ProgramPlayDialog.createAndShowGUI(code, null, null);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
/*
|
||||||
|
* center text panel
|
||||||
|
*/
|
||||||
|
JPanel centerPanel = new JPanel();
|
||||||
|
panel.add(centerPanel);
|
||||||
|
|
||||||
|
txaPrinter = new WindowTextArea();
|
||||||
|
centerPanel.add(txaPrinter);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* bottom data panel
|
||||||
|
*/
|
||||||
|
// data type choice boxes
|
||||||
|
Box Hbox = Box.createHorizontalBox();
|
||||||
|
panel.add(Hbox);
|
||||||
|
|
||||||
|
Box VBox1 = Box.createVerticalBox();
|
||||||
|
JLabel l1 = new JLabel("Key Encoding");
|
||||||
|
l1.setAlignmentX(Component.CENTER_ALIGNMENT);
|
||||||
|
JComboBox cmbKey = new JComboBox(dataTypes);
|
||||||
|
cmbKey.setSelectedIndex(1);
|
||||||
|
cmbKey.addActionListener(new ActionListener() {
|
||||||
|
public void actionPerformed(ActionEvent e) {
|
||||||
|
JComboBox cmb = (JComboBox) e.getSource();
|
||||||
|
DataEncodingType t = DataEncodingType.getTypeFromString((String) cmb.getSelectedItem());
|
||||||
|
dataModel.setKeyEncoding(t);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
VBox1.add(l1);
|
||||||
|
VBox1.add(cmbKey);
|
||||||
|
|
||||||
|
Box VBox2 = Box.createVerticalBox();
|
||||||
|
VBox2.setAlignmentX(LEFT_ALIGNMENT);
|
||||||
|
JLabel l2 = new JLabel("Value Encoding");
|
||||||
|
l2.setAlignmentX(Component.CENTER_ALIGNMENT);
|
||||||
|
JComboBox cmbValue = new JComboBox(dataTypes);
|
||||||
|
cmbValue.setSelectedIndex(1);
|
||||||
|
cmbValue.addActionListener(new ActionListener() {
|
||||||
|
public void actionPerformed(ActionEvent e) {
|
||||||
|
JComboBox cmb = (JComboBox) e.getSource();
|
||||||
|
DataEncodingType t = DataEncodingType.getTypeFromString((String) cmb.getSelectedItem());
|
||||||
|
dataModel.setValueEncoding(t);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
VBox2.add(l2);
|
||||||
|
VBox2.add(cmbValue);
|
||||||
|
|
||||||
|
Hbox.add(VBox1);
|
||||||
|
|
||||||
|
JPanel spacer = new JPanel();
|
||||||
|
FlowLayout flowLayout = (FlowLayout) spacer.getLayout();
|
||||||
|
flowLayout.setHgap(100);
|
||||||
|
Hbox.add(spacer);
|
||||||
|
Hbox.add(VBox2);
|
||||||
|
|
||||||
|
// table
|
||||||
|
tblStateDataTable = new JTable();
|
||||||
|
dataModel = new StateDataTableModel();
|
||||||
|
tblStateDataTable.setModel(dataModel);
|
||||||
|
|
||||||
|
|
||||||
|
JScrollPane scrollPane = new JScrollPane(tblStateDataTable);
|
||||||
|
scrollPane.setPreferredSize(new Dimension(600,200));
|
||||||
|
panel.add(scrollPane);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void searchAccount(String accountStr){
|
||||||
|
txaPrinter.clean();
|
||||||
|
|
||||||
|
byte[] add = null;
|
||||||
|
try { add = Hex.decode(txfAccountAddress.getText()); }
|
||||||
|
catch(DecoderException ex) { return; }
|
||||||
|
|
||||||
|
txaPrinter.println(accountDetailsString(add, dataModel));
|
||||||
|
}
|
||||||
|
|
||||||
|
private String accountDetailsString(byte[] account, StateDataTableModel dataModel){
|
||||||
|
String ret = "";
|
||||||
|
// 1) print account address
|
||||||
|
ret = "Account: " + Hex.toHexString(account) + "\n";
|
||||||
|
|
||||||
|
//2) print state
|
||||||
|
AccountState state = WorldManager.getInstance().getRepository().getAccountState(account);
|
||||||
|
if(state != null)
|
||||||
|
ret += state.toString() + "\n";
|
||||||
|
|
||||||
|
//3) print storage
|
||||||
|
ContractDetails contractDetails = WorldManager.getInstance().getRepository().getContractDetails(account);
|
||||||
|
if(contractDetails != null) {
|
||||||
|
Map<DataWord, DataWord> accountStorage = contractDetails.getStorage();
|
||||||
|
dataModel.setData(accountStorage);
|
||||||
|
}
|
||||||
|
|
||||||
|
//4) code print
|
||||||
|
byte[] code = WorldManager.getInstance().getRepository().getCode(account);
|
||||||
|
if(code != null) {
|
||||||
|
ret += "\n\nCode:\n";
|
||||||
|
ret += Program.stringify(code, 0, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
private class StateDataTableModel extends AbstractTableModel {
|
||||||
|
|
||||||
|
Map<DataWord, DataWord> data;
|
||||||
|
DataEncodingType keyEncodingType = DataEncodingType.HEX;
|
||||||
|
DataEncodingType valueEncodingType = DataEncodingType.HEX;
|
||||||
|
String[] columns = new String[]{ "Key", "Value"};
|
||||||
|
|
||||||
|
public StateDataTableModel() { }
|
||||||
|
|
||||||
|
public StateDataTableModel(Map<DataWord, DataWord> initData) {
|
||||||
|
setData(initData);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setData(Map<DataWord, DataWord> initData) {
|
||||||
|
data = initData;
|
||||||
|
fireTableDataChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setKeyEncoding(DataEncodingType type) {
|
||||||
|
keyEncodingType = type;
|
||||||
|
fireTableDataChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setValueEncoding(DataEncodingType type) {
|
||||||
|
valueEncodingType = type;
|
||||||
|
fireTableDataChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getColumnName(int column) {
|
||||||
|
return columns[column];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getRowCount() {
|
||||||
|
return data == null? 0:data.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getColumnCount() {
|
||||||
|
return columns.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object getValueAt(int rowIndex, int columnIndex) {
|
||||||
|
DataWord key = (DataWord) this.data.keySet().toArray()[rowIndex];
|
||||||
|
|
||||||
|
if(columnIndex == 0) {
|
||||||
|
return getDataWithEncoding(key.getData(), keyEncodingType);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
DataWord value = this.data.get(key);
|
||||||
|
return getDataWithEncoding(value.getData(), valueEncodingType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getDataWithEncoding(byte[] data, DataEncodingType enc) {
|
||||||
|
switch(enc) {
|
||||||
|
case STRING:
|
||||||
|
return new String(data);
|
||||||
|
case HEX:
|
||||||
|
return Hex.toHexString(data);
|
||||||
|
case NUMBER:
|
||||||
|
return new BigInteger(data).toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
return data.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private enum DataEncodingType{
|
||||||
|
STRING,
|
||||||
|
HEX,
|
||||||
|
NUMBER;
|
||||||
|
|
||||||
|
static public DataEncodingType getTypeFromString(String value) {
|
||||||
|
switch(value){
|
||||||
|
case "String":
|
||||||
|
return STRING;
|
||||||
|
case "Hex":
|
||||||
|
return HEX;
|
||||||
|
case "Number":
|
||||||
|
return NUMBER;
|
||||||
|
}
|
||||||
|
return STRING;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class WindowTextArea extends TextArea {
|
||||||
|
|
||||||
|
public WindowTextArea() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void println(String txt) {
|
||||||
|
setText(getText() + txt + "\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void clean() {
|
||||||
|
setText("");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
// Start all Swing applications on the EDT.
|
||||||
|
SwingUtilities.invokeLater(new Runnable() {
|
||||||
|
public void run() {
|
||||||
|
new StateExplorerWindow(null).setVisible(true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -28,12 +28,14 @@ public class ToolBar extends JFrame {
|
||||||
private BlockChainTable blockchainWindow = null;
|
private BlockChainTable blockchainWindow = null;
|
||||||
private WalletWindow walletWindow = null;
|
private WalletWindow walletWindow = null;
|
||||||
private SerpentEditor serpentEditor = null;
|
private SerpentEditor serpentEditor = null;
|
||||||
|
private StateExplorerWindow stateExplorerWindow = null;
|
||||||
|
|
||||||
JToggleButton editorToggle;
|
JToggleButton editorToggle;
|
||||||
JToggleButton logToggle;
|
JToggleButton logToggle;
|
||||||
JToggleButton peersToggle;
|
JToggleButton peersToggle;
|
||||||
JToggleButton chainToggle;
|
JToggleButton chainToggle;
|
||||||
JToggleButton walletToggle;
|
JToggleButton walletToggle;
|
||||||
|
JToggleButton stateExplorer;
|
||||||
|
|
||||||
public ToolBar() throws HeadlessException {
|
public ToolBar() throws HeadlessException {
|
||||||
|
|
||||||
|
@ -94,6 +96,9 @@ public class ToolBar extends JFrame {
|
||||||
|
|
||||||
java.net.URL imageURL_5 = ClassLoader.getSystemResource("buttons/wallet.png");
|
java.net.URL imageURL_5 = ClassLoader.getSystemResource("buttons/wallet.png");
|
||||||
ImageIcon image_5 = new ImageIcon(imageURL_5);
|
ImageIcon image_5 = new ImageIcon(imageURL_5);
|
||||||
|
|
||||||
|
java.net.URL imageURL_6 = ClassLoader.getSystemResource("buttons/stateExplorer.png");
|
||||||
|
ImageIcon image_6 = new ImageIcon(imageURL_6);
|
||||||
|
|
||||||
editorToggle = new JToggleButton("");
|
editorToggle = new JToggleButton("");
|
||||||
editorToggle.setIcon(image_1);
|
editorToggle.setIcon(image_1);
|
||||||
|
@ -222,12 +227,41 @@ public class ToolBar extends JFrame {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
stateExplorer = new JToggleButton();
|
||||||
|
stateExplorer.setIcon(image_6);
|
||||||
|
stateExplorer.setToolTipText("State Explorer");
|
||||||
|
stateExplorer.setContentAreaFilled(true);
|
||||||
|
stateExplorer.setBackground(Color.WHITE);
|
||||||
|
stateExplorer.setBorderPainted(false);
|
||||||
|
stateExplorer.setFocusPainted(false);
|
||||||
|
stateExplorer.setCursor(new Cursor(Cursor.HAND_CURSOR));
|
||||||
|
stateExplorer.addItemListener(
|
||||||
|
new ItemListener() {
|
||||||
|
@Override
|
||||||
|
public void itemStateChanged(ItemEvent e) {
|
||||||
|
if (e.getStateChange() == ItemEvent.SELECTED) {
|
||||||
|
SwingUtilities.invokeLater(new Runnable() {
|
||||||
|
public void run() {
|
||||||
|
if (stateExplorerWindow == null)
|
||||||
|
stateExplorerWindow = new StateExplorerWindow(ToolBar.this);
|
||||||
|
stateExplorerWindow.setVisible(true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else if (e.getStateChange() == ItemEvent.DESELECTED) {
|
||||||
|
stateExplorerWindow.setVisible(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
cp.add(editorToggle);
|
cp.add(editorToggle);
|
||||||
cp.add(logToggle);
|
cp.add(logToggle);
|
||||||
cp.add(peersToggle);
|
cp.add(peersToggle);
|
||||||
cp.add(chainToggle);
|
cp.add(chainToggle);
|
||||||
cp.add(walletToggle);
|
cp.add(walletToggle);
|
||||||
|
cp.add(stateExplorer);
|
||||||
|
|
||||||
Ethereum ethereum = UIEthereumManager.ethereum;
|
Ethereum ethereum = UIEthereumManager.ethereum;
|
||||||
|
|
||||||
|
|
Binary file not shown.
After Width: | Height: | Size: 415 B |
Binary file not shown.
After Width: | Height: | Size: 927 B |
Loading…
Reference in New Issue