Contract Call Dialog:

+ Play button to call already saved contracts
This commit is contained in:
romanman 2014-06-09 14:45:41 +01:00
parent a9b890a86d
commit 9ae78521a6
4 changed files with 93 additions and 22 deletions

View File

@ -1,8 +1,10 @@
package org.ethereum.gui; package org.ethereum.gui;
import org.ethereum.core.Account; import org.ethereum.core.Account;
import org.ethereum.core.AccountState;
import org.ethereum.core.Transaction; import org.ethereum.core.Transaction;
import org.ethereum.manager.MainData; import org.ethereum.manager.MainData;
import org.ethereum.manager.WorldManager;
import org.ethereum.net.client.ClientPeer; import org.ethereum.net.client.ClientPeer;
import org.ethereum.util.ByteUtil; import org.ethereum.util.ByteUtil;
import org.ethereum.util.Utils; import org.ethereum.util.Utils;
@ -32,7 +34,7 @@ import java.util.Collection;
*/ */
class ContractCallDialog extends JDialog implements MessageAwareDialog{ class ContractCallDialog extends JDialog implements MessageAwareDialog{
Logger logger = LoggerFactory.getLogger(getClass()); Logger logger = LoggerFactory.getLogger("ui");
ContractCallDialog dialog; ContractCallDialog dialog;
@ -79,6 +81,24 @@ class ContractCallDialog extends JDialog implements MessageAwareDialog{
rejectLabel.setToolTipText("Cancel"); rejectLabel.setToolTipText("Cancel");
rejectLabel.setCursor(new Cursor(Cursor.HAND_CURSOR)); rejectLabel.setCursor(new Cursor(Cursor.HAND_CURSOR));
URL playIconURL = ClassLoader.getSystemResource("buttons/play.png");
ImageIcon playIcon = new ImageIcon(playIconURL);
JLabel playLabel = new JLabel(playIcon);
playLabel.setToolTipText("Play Drafted");
playLabel.setCursor(new Cursor(Cursor.HAND_CURSOR));
playLabel.addMouseListener(
new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
ContractCallDialog.this.playContractCall();
}}
);
playLabel.setBounds(438, 100, 42, 42);
this.getContentPane().add(playLabel);
JLabel statusMessage = new JLabel(""); JLabel statusMessage = new JLabel("");
statusMessage.setBounds(50, 360, 400, 50); statusMessage.setBounds(50, 360, 400, 50);
statusMessage.setHorizontalAlignment(SwingConstants.CENTER); statusMessage.setHorizontalAlignment(SwingConstants.CENTER);
@ -178,6 +198,29 @@ class ContractCallDialog extends JDialog implements MessageAwareDialog{
this.setResizable(false); this.setResizable(false);
} }
private void playContractCall() {
byte[] contractAddress = Hex.decode( contractAddrInput.getText());
byte[] contractStateB = WorldManager.instance.worldState.get(contractAddress);
if (contractStateB == null || contractStateB.length == 0){
alertStatusMsg("No contract for that address");
return;
}
AccountState contractState = new AccountState(contractStateB);
byte[] programCode = WorldManager.instance.chainDB.get(contractState.getCodeHash());
if (programCode == null || programCode.length == 0){
alertStatusMsg("Such account exist but no code in the db");
return;
}
Transaction tx = createTransaction();
if (tx == null) return;
ProgramPlayDialog.createAndShowGUI(programCode, tx, MainData.instance.getBlockchain().getLastBlock());
}
protected JRootPane createRootPane() { protected JRootPane createRootPane() {
Container parent = this.getParent(); Container parent = this.getParent();
@ -223,9 +266,28 @@ class ContractCallDialog extends JDialog implements MessageAwareDialog{
return; return;
} }
// todo: check up how the HEX value is encoded Transaction tx = createTransaction();
Object[] lexaList = msgDataTA.getText().split(","); if (tx == null) return;
byte[] data = ByteUtil.encodeDataList(lexaList);
if (logger.isInfoEnabled()) {
logger.info("tx.hash: {}", (new BigInteger(tx.getHash()).toString(16)));
}
// SwingWorker
DialogWorker worker = new DialogWorker(tx, this);
worker.execute();
}
private Transaction createTransaction(){
byte[] data;
if (!msgDataTA.getText().trim().equals("")){
Object[] lexaList = msgDataTA.getText().split(",");
data = ByteUtil.encodeDataList(lexaList);
} else {
data = new byte[]{};
}
byte[] contractAddress = Hex.decode( contractAddrInput.getText()); byte[] contractAddress = Hex.decode( contractAddrInput.getText());
@ -249,26 +311,21 @@ class ContractCallDialog extends JDialog implements MessageAwareDialog{
logger.info("tx.data: {}", Hex.toHexString(data)); logger.info("tx.data: {}", Hex.toHexString(data));
} }
Transaction tx = new Transaction(nonce, gasPrice, gasValue, Transaction tx = new Transaction(nonce, gasPrice, gasValue,
contractAddress, endowment, data); contractAddress, endowment, data);
if (logger.isInfoEnabled()) {
logger.info("tx.hash: {}", (new BigInteger(tx.getHash()).toString(16)));
}
try { try {
tx.sign(senderPrivKey); tx.sign(senderPrivKey);
} catch (Exception e1) { } catch (Exception e1) {
dialog.alertStatusMsg("Failed to sign the transaction"); dialog.alertStatusMsg("Failed to sign the transaction");
return; return null;
} }
// SwingWorker return tx;
DialogWorker worker = new DialogWorker(tx, this);
worker.execute();
} }
public class AccountWrapper { public class AccountWrapper {
private Account account; private Account account;

View File

@ -4,6 +4,7 @@ import org.ethereum.core.Account;
import org.ethereum.core.AccountState; import org.ethereum.core.AccountState;
import org.ethereum.core.Transaction; import org.ethereum.core.Transaction;
import org.ethereum.manager.MainData; import org.ethereum.manager.MainData;
import org.ethereum.manager.WorldManager;
import org.ethereum.net.client.ClientPeer; import org.ethereum.net.client.ClientPeer;
import org.ethereum.util.Utils; import org.ethereum.util.Utils;
import org.spongycastle.util.BigIntegers; import org.spongycastle.util.BigIntegers;
@ -107,7 +108,7 @@ class ContractSubmitDialog extends JDialog implements MessageAwareDialog {
} }
contractAddrInput.setText(Hex.toHexString(tx.getContractAddress())); contractAddrInput.setText(Hex.toHexString(tx.getContractAddress()));
ProgramPlayDialog.createAndShowGUI(tx); ProgramPlayDialog.createAndShowGUI(tx.getData(), tx, MainData.instance.getBlockchain().getLastBlock());
}} }}
); );
@ -312,7 +313,7 @@ class ContractSubmitDialog extends JDialog implements MessageAwareDialog {
Account account = ((AccountWrapper)creatorAddressCombo.getSelectedItem()).getAccount(); Account account = ((AccountWrapper)creatorAddressCombo.getSelectedItem()).getAccount();
BigInteger currentBalance = account.getState().getBalance(); BigInteger currentBalance = account.getState().getBalance();
BigInteger gasPrice = BigInteger.valueOf( MainData.instance.getBlockchain().getGasPrice()); BigInteger gasPrice = BigInteger.valueOf(MainData.instance.getBlockchain().getGasPrice());
BigInteger gasInput = new BigInteger( this.gasInput.getText()); BigInteger gasInput = new BigInteger( this.gasInput.getText());
boolean canAfford = currentBalance.compareTo(gasPrice.multiply(gasInput)) >= 0; boolean canAfford = currentBalance.compareTo(gasPrice.multiply(gasInput)) >= 0;

View File

@ -1,5 +1,6 @@
package org.ethereum.gui; package org.ethereum.gui;
import org.ethereum.core.Block;
import org.ethereum.core.Transaction; import org.ethereum.core.Transaction;
import org.ethereum.vm.Program; import org.ethereum.vm.Program;
import org.ethereum.vm.ProgramInvokeFactory; import org.ethereum.vm.ProgramInvokeFactory;
@ -31,7 +32,7 @@ public class ProgramPlayDialog extends JPanel implements ActionListener,
private Transaction tx; private Transaction tx;
public ProgramPlayDialog(Transaction tx) { public ProgramPlayDialog(byte[] code, Transaction tx, Block lastBlock) {
this.tx = tx; this.tx = tx;
@ -46,8 +47,8 @@ public class ProgramPlayDialog extends JPanel implements ActionListener,
// byte[] codeBytes = // byte[] codeBytes =
// Hex.decode(code); // Hex.decode(code);
Program program = new Program(tx.getData() , Program program = new Program(code ,
ProgramInvokeFactory.createProgramInvoke(tx, null)); ProgramInvokeFactory.createProgramInvoke(tx, lastBlock));
program.addListener(this); program.addListener(this);
program.fullTrace(); program.fullTrace();
@ -128,9 +129,9 @@ public class ProgramPlayDialog extends JPanel implements ActionListener,
* this method should be invoked from the * this method should be invoked from the
* event-dispatching thread. * event-dispatching thread.
*/ */
public static void createAndShowGUI(Transaction tx) { public static void createAndShowGUI(byte[] runCode, Transaction tx, Block lastBlock) {
ProgramPlayDialog ppd = new ProgramPlayDialog(tx); ProgramPlayDialog ppd = new ProgramPlayDialog(runCode, tx, lastBlock);
//Create and set up the window. //Create and set up the window.
JFrame frame = new JFrame("Program Draft Play"); JFrame frame = new JFrame("Program Draft Play");

View File

@ -72,7 +72,11 @@ public class Program {
if (this.pc > ops.length) { if (this.pc > ops.length) {
stop(); stop();
throw new RuntimeException("pc overflow pc: " + pc); throw new RuntimeException("pc overflow pc= " + pc);
}
if (this.pc == ops.length) {
stop();
} }
} }
@ -386,8 +390,16 @@ public class Program {
globalOutput.append("\n HReturn: ").append(Hex.toHexString(result.gethReturn().array())); globalOutput.append("\n HReturn: ").append(Hex.toHexString(result.gethReturn().array()));
} }
// soffisticated assumption that msg.data != codedata
// means we are calling the contract not creating it
byte[] txData = invokeData.getDataCopy(DataWord.ZERO, getDataSize());
if (!Arrays.equals(txData, ops)){
globalOutput.append("\n msg.data: ").append(Hex.toHexString( txData ));
}
globalOutput.append("\n\n Spent Gas: ").append(result.getGasUsed()); globalOutput.append("\n\n Spent Gas: ").append(result.getGasUsed());
if (listener != null){ if (listener != null){
listener.output(globalOutput.toString()); listener.output(globalOutput.toString());
} }