diff --git a/ethereumj-core/src/main/java/org/ethereum/gui/ContractCallDialog.java b/ethereumj-core/src/main/java/org/ethereum/gui/ContractCallDialog.java index cd5498fc..9046a5cb 100644 --- a/ethereumj-core/src/main/java/org/ethereum/gui/ContractCallDialog.java +++ b/ethereumj-core/src/main/java/org/ethereum/gui/ContractCallDialog.java @@ -1,8 +1,10 @@ package org.ethereum.gui; import org.ethereum.core.Account; +import org.ethereum.core.AccountState; import org.ethereum.core.Transaction; import org.ethereum.manager.MainData; +import org.ethereum.manager.WorldManager; import org.ethereum.net.client.ClientPeer; import org.ethereum.util.ByteUtil; import org.ethereum.util.Utils; @@ -32,7 +34,7 @@ import java.util.Collection; */ class ContractCallDialog extends JDialog implements MessageAwareDialog{ - Logger logger = LoggerFactory.getLogger(getClass()); + Logger logger = LoggerFactory.getLogger("ui"); ContractCallDialog dialog; @@ -79,6 +81,24 @@ class ContractCallDialog extends JDialog implements MessageAwareDialog{ rejectLabel.setToolTipText("Cancel"); 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(""); statusMessage.setBounds(50, 360, 400, 50); statusMessage.setHorizontalAlignment(SwingConstants.CENTER); @@ -178,6 +198,29 @@ class ContractCallDialog extends JDialog implements MessageAwareDialog{ 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() { Container parent = this.getParent(); @@ -223,9 +266,28 @@ class ContractCallDialog extends JDialog implements MessageAwareDialog{ return; } - // todo: check up how the HEX value is encoded - Object[] lexaList = msgDataTA.getText().split(","); - byte[] data = ByteUtil.encodeDataList(lexaList); + Transaction tx = createTransaction(); + if (tx == null) return; + + 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()); @@ -249,26 +311,21 @@ class ContractCallDialog extends JDialog implements MessageAwareDialog{ logger.info("tx.data: {}", Hex.toHexString(data)); } - Transaction tx = new Transaction(nonce, gasPrice, gasValue, - contractAddress, endowment, data); - - if (logger.isInfoEnabled()) { - logger.info("tx.hash: {}", (new BigInteger(tx.getHash()).toString(16))); - } + Transaction tx = new Transaction(nonce, gasPrice, gasValue, + contractAddress, endowment, data); try { tx.sign(senderPrivKey); } catch (Exception e1) { dialog.alertStatusMsg("Failed to sign the transaction"); - return; + return null; } - // SwingWorker - DialogWorker worker = new DialogWorker(tx, this); - worker.execute(); + return tx; } + public class AccountWrapper { private Account account; diff --git a/ethereumj-core/src/main/java/org/ethereum/gui/ContractSubmitDialog.java b/ethereumj-core/src/main/java/org/ethereum/gui/ContractSubmitDialog.java index 1fae8123..51cb2832 100644 --- a/ethereumj-core/src/main/java/org/ethereum/gui/ContractSubmitDialog.java +++ b/ethereumj-core/src/main/java/org/ethereum/gui/ContractSubmitDialog.java @@ -4,6 +4,7 @@ import org.ethereum.core.Account; import org.ethereum.core.AccountState; import org.ethereum.core.Transaction; import org.ethereum.manager.MainData; +import org.ethereum.manager.WorldManager; import org.ethereum.net.client.ClientPeer; import org.ethereum.util.Utils; import org.spongycastle.util.BigIntegers; @@ -107,7 +108,7 @@ class ContractSubmitDialog extends JDialog implements MessageAwareDialog { } 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(); 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()); boolean canAfford = currentBalance.compareTo(gasPrice.multiply(gasInput)) >= 0; diff --git a/ethereumj-core/src/main/java/org/ethereum/gui/ProgramPlayDialog.java b/ethereumj-core/src/main/java/org/ethereum/gui/ProgramPlayDialog.java index a1de74f3..cf66d022 100644 --- a/ethereumj-core/src/main/java/org/ethereum/gui/ProgramPlayDialog.java +++ b/ethereumj-core/src/main/java/org/ethereum/gui/ProgramPlayDialog.java @@ -1,5 +1,6 @@ package org.ethereum.gui; +import org.ethereum.core.Block; import org.ethereum.core.Transaction; import org.ethereum.vm.Program; import org.ethereum.vm.ProgramInvokeFactory; @@ -31,7 +32,7 @@ public class ProgramPlayDialog extends JPanel implements ActionListener, private Transaction tx; - public ProgramPlayDialog(Transaction tx) { + public ProgramPlayDialog(byte[] code, Transaction tx, Block lastBlock) { this.tx = tx; @@ -46,8 +47,8 @@ public class ProgramPlayDialog extends JPanel implements ActionListener, // byte[] codeBytes = // Hex.decode(code); - Program program = new Program(tx.getData() , - ProgramInvokeFactory.createProgramInvoke(tx, null)); + Program program = new Program(code , + ProgramInvokeFactory.createProgramInvoke(tx, lastBlock)); program.addListener(this); program.fullTrace(); @@ -128,9 +129,9 @@ public class ProgramPlayDialog extends JPanel implements ActionListener, * this method should be invoked from the * 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. JFrame frame = new JFrame("Program Draft Play"); diff --git a/ethereumj-core/src/main/java/org/ethereum/vm/Program.java b/ethereumj-core/src/main/java/org/ethereum/vm/Program.java index 1f5d2b69..59040083 100644 --- a/ethereumj-core/src/main/java/org/ethereum/vm/Program.java +++ b/ethereumj-core/src/main/java/org/ethereum/vm/Program.java @@ -72,7 +72,11 @@ public class Program { if (this.pc > ops.length) { 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())); } + // 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()); + if (listener != null){ listener.output(globalOutput.toString()); }