From 11e9190957fd704ed265d2c4379964a19344e93e Mon Sep 17 00:00:00 2001 From: romanman Date: Wed, 11 Jun 2014 09:56:18 +0100 Subject: [PATCH] Contract Call impl: + Contract storage local save --- .../org/ethereum/core/ContractDetails.java | 106 ++++++++++++++++++ .../org/ethereum/gui/ContractCallDialog.java | 10 +- .../ethereum/gui/ContractSubmitDialog.java | 3 +- .../org/ethereum/gui/ProgramPlayDialog.java | 25 ++--- .../java/org/ethereum/manager/MainData.java | 5 +- .../org/ethereum/manager/WorldManager.java | 49 ++++++-- .../main/java/org/ethereum/vm/Program.java | 10 ++ .../java/org/ethereum/vm/ProgramInvoke.java | 4 + .../org/ethereum/vm/ProgramInvokeFactory.java | 18 +-- .../org/ethereum/vm/ProgramInvokeImpl.java | 10 +- .../java/org/ethereum/vm/ProgramResult.java | 10 ++ .../src/main/java/org/ethereum/vm/VM.java | 3 +- .../ethereum/core/ContractDetailsTest.java | 90 +++++++++++++++ .../ethereum/serpent/MachineCompileTest.java | 21 ++++ .../ethereum/vm/ProgramInvokeMockImpl.java | 7 ++ 15 files changed, 328 insertions(+), 43 deletions(-) create mode 100644 ethereumj-core/src/main/java/org/ethereum/core/ContractDetails.java create mode 100644 ethereumj-core/src/test/java/org/ethereum/core/ContractDetailsTest.java diff --git a/ethereumj-core/src/main/java/org/ethereum/core/ContractDetails.java b/ethereumj-core/src/main/java/org/ethereum/core/ContractDetails.java new file mode 100644 index 00000000..dd5083a1 --- /dev/null +++ b/ethereumj-core/src/main/java/org/ethereum/core/ContractDetails.java @@ -0,0 +1,106 @@ +package org.ethereum.core; + +import org.ethereum.util.RLP; +import org.ethereum.util.RLPElement; +import org.ethereum.util.RLPItem; +import org.ethereum.util.RLPList; +import org.ethereum.vm.DataWord; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * www.ethereumJ.com + * + * @author: Roman Mandeleil + * Created on: 09/06/2014 15:31 + */ + +public class ContractDetails { + + private byte[] rlpEncoded; + + List storageKeys; + List storageValues; + + public ContractDetails(byte[] rlpEncoded) { + + RLPList data = RLP.decode2(rlpEncoded); + RLPList rlpList = (RLPList)data.get(0); + + RLPList keys = (RLPList)rlpList.get(0); + RLPList values = (RLPList)rlpList.get(1); + + if (keys.size() > 0){ + storageKeys = new ArrayList<>(); + storageValues = new ArrayList<>(); + } + + for (int i = 0; i < keys.size(); ++i){ + + RLPItem rlpItem = (RLPItem)keys.get(i); + storageKeys.add(new DataWord(rlpItem.getRLPData())); + } + + for (int i = 0; i < values.size(); ++i){ + RLPItem rlpItem = (RLPItem)values.get(i); + storageValues.add(new DataWord(rlpItem.getRLPData())); + } + + System.out.println(); + } + + public ContractDetails(Map storage) { + + storageKeys = new ArrayList(); + storageValues = new ArrayList(); + + for(DataWord key : storage.keySet()){ + + DataWord value = storage.get(key); + + storageKeys.add(key); + storageValues.add(value); + } + } + + public byte[] getEncoded() { + if(rlpEncoded == null) { + + byte[][] keys = new byte[storageKeys.size()][]; + byte[][] values = new byte[storageValues.size()][]; + + int i = 0; + for (DataWord key : storageKeys){ + keys[i] = RLP.encodeElement( key.getData()); + ++i; + } + + i = 0; + for (DataWord value : storageValues){ + values[i] = RLP.encodeElement( value.getData() ); + ++i; + } + + byte[] rlpKeysList = RLP.encodeList(keys); + byte[] rlpValuesList = RLP.encodeList(values); + + this.rlpEncoded = RLP.encodeList(rlpKeysList, rlpValuesList); + } + return rlpEncoded; + } + + + public Map getStorage(){ + + Map storage = new HashMap<>(); + + for (int i = 0; i < storageKeys.size(); ++i){ + storage.put(storageKeys.get(i), storageValues.get(i)); + } + + return storage; + } +} 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 9046a5cb..795cac7e 100644 --- a/ethereumj-core/src/main/java/org/ethereum/gui/ContractCallDialog.java +++ b/ethereumj-core/src/main/java/org/ethereum/gui/ContractCallDialog.java @@ -2,6 +2,7 @@ package org.ethereum.gui; import org.ethereum.core.Account; import org.ethereum.core.AccountState; +import org.ethereum.core.ContractDetails; import org.ethereum.core.Transaction; import org.ethereum.manager.MainData; import org.ethereum.manager.WorldManager; @@ -215,10 +216,17 @@ class ContractCallDialog extends JDialog implements MessageAwareDialog{ return; } + byte[] contractDetailsB = + WorldManager.instance.detaildDB.get(contractAddress); + + ContractDetails contractDetails = null; + if (contractDetailsB.length > 0) + contractDetails = new ContractDetails(contractDetailsB); + Transaction tx = createTransaction(); if (tx == null) return; - ProgramPlayDialog.createAndShowGUI(programCode, tx, MainData.instance.getBlockchain().getLastBlock()); + ProgramPlayDialog.createAndShowGUI(programCode, tx, MainData.instance.getBlockchain().getLastBlock(), contractDetails); } protected JRootPane createRootPane() { 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 51cb2832..d7ca24f7 100644 --- a/ethereumj-core/src/main/java/org/ethereum/gui/ContractSubmitDialog.java +++ b/ethereumj-core/src/main/java/org/ethereum/gui/ContractSubmitDialog.java @@ -108,7 +108,8 @@ class ContractSubmitDialog extends JDialog implements MessageAwareDialog { } contractAddrInput.setText(Hex.toHexString(tx.getContractAddress())); - ProgramPlayDialog.createAndShowGUI(tx.getData(), tx, MainData.instance.getBlockchain().getLastBlock()); + ProgramPlayDialog.createAndShowGUI(tx.getData(), tx, + MainData.instance.getBlockchain().getLastBlock(), null); }} ); 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 cf66d022..5a05579f 100644 --- a/ethereumj-core/src/main/java/org/ethereum/gui/ProgramPlayDialog.java +++ b/ethereumj-core/src/main/java/org/ethereum/gui/ProgramPlayDialog.java @@ -1,6 +1,7 @@ package org.ethereum.gui; import org.ethereum.core.Block; +import org.ethereum.core.ContractDetails; import org.ethereum.core.Transaction; import org.ethereum.vm.Program; import org.ethereum.vm.ProgramInvokeFactory; @@ -32,29 +33,19 @@ public class ProgramPlayDialog extends JPanel implements ActionListener, private Transaction tx; - public ProgramPlayDialog(byte[] code, Transaction tx, Block lastBlock) { + public ProgramPlayDialog(byte[] code, Transaction tx, Block lastBlock, ContractDetails contractDetails) { this.tx = tx; outputList = new ArrayList(); VM vm = new VM(); -// Program program = new Program(Hex.decode("630000000060445960CC60DD611234600054615566602054630000000060445960CC60DD611234600054615566602054630000000060445960CC60DD611234600054615566602054")); -// Program program = new Program(Hex.decode("60016023576000605f556014600054601e60205463abcddcba6040545b51602001600a5254516040016014525451606001601e5254516080016028525460a052546016604860003960166000f26000603f556103e75660005460005360200235602054"), null); - -// String code = "60016000546006601160003960066000f261778e600054"; -// String code = "620f424073cd2a3d9f938e13cd947ec05abc7fe734df8dd826576086602660003960866000f26001602036040e0f630000002159600060200235600054600053565b525b54602052f263000000765833602054602053566040546000602002356060546001602002356080546080536040530a0f0f630000006c59608053604053036020535760805360605356016060535760015b525b54602052f263000000765860005b525b54602052f2"; - -// byte[] codeBytes = -// Hex.decode(code); Program program = new Program(code , - ProgramInvokeFactory.createProgramInvoke(tx, lastBlock)); + ProgramInvokeFactory.createProgramInvoke(tx, lastBlock, contractDetails)); program.addListener(this); program.fullTrace(); - - while(!program.isStopped()) - vm.step(program); + vm.play(program); setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS)); @@ -70,6 +61,9 @@ public class ProgramPlayDialog extends JPanel implements ActionListener, stepSlider.setMajorTickSpacing(1); if (outputList.size() > 40) stepSlider.setMajorTickSpacing(3); + if (outputList.size() > 100) + stepSlider.setMajorTickSpacing(20); + stepSlider.setMinorTickSpacing(1); stepSlider.setPaintTicks(true); @@ -129,9 +123,9 @@ public class ProgramPlayDialog extends JPanel implements ActionListener, * this method should be invoked from the * event-dispatching thread. */ - public static void createAndShowGUI(byte[] runCode, Transaction tx, Block lastBlock) { + public static void createAndShowGUI(byte[] runCode, Transaction tx, Block lastBlock, ContractDetails details) { - ProgramPlayDialog ppd = new ProgramPlayDialog(runCode, tx, lastBlock); + ProgramPlayDialog ppd = new ProgramPlayDialog(runCode, tx, lastBlock, details); //Create and set up the window. JFrame frame = new JFrame("Program Draft Play"); @@ -142,7 +136,6 @@ public class ProgramPlayDialog extends JPanel implements ActionListener, Image img = kit.createImage(url); frame.setIconImage(img); - frame.setPreferredSize(new Dimension(580, 500)); frame.setLocation(400, 200); diff --git a/ethereumj-core/src/main/java/org/ethereum/manager/MainData.java b/ethereumj-core/src/main/java/org/ethereum/manager/MainData.java index 8b6e3d47..87f8e1f1 100644 --- a/ethereumj-core/src/main/java/org/ethereum/manager/MainData.java +++ b/ethereumj-core/src/main/java/org/ethereum/manager/MainData.java @@ -45,11 +45,12 @@ public class MainData { // Initialize Wallet byte[] cowAddr = HashUtil.sha3("cow".getBytes()); ECKey key = ECKey.fromPrivate(cowAddr); - wallet.importKey(cowAddr); + AccountState state = wallet.getAccountState(key.getAddress()); state.addToBalance(BigInteger.valueOf(2).pow(200)); - wallet.importKey(HashUtil.sha3("cat".getBytes())); + +// wallet.importKey(HashUtil.sha3("cat".getBytes())); String secret = CONFIG.coinbaseSecret(); byte[] cbAddr = HashUtil.sha3(secret.getBytes()); diff --git a/ethereumj-core/src/main/java/org/ethereum/manager/WorldManager.java b/ethereumj-core/src/main/java/org/ethereum/manager/WorldManager.java index 05ce5bc6..f7e6a0e9 100644 --- a/ethereumj-core/src/main/java/org/ethereum/manager/WorldManager.java +++ b/ethereumj-core/src/main/java/org/ethereum/manager/WorldManager.java @@ -2,6 +2,7 @@ package org.ethereum.manager; import org.ethereum.core.AccountState; import org.ethereum.core.Block; +import org.ethereum.core.ContractDetails; import org.ethereum.core.Transaction; import org.ethereum.crypto.HashUtil; import org.ethereum.db.Database; @@ -36,8 +37,9 @@ public class WorldManager { private Map pendingTransactions = Collections.synchronizedMap(new HashMap()); - public Database chainDB = new Database("blockchain"); - public Database stateDB = new Database("state"); + public Database chainDB = new Database("blockchain"); + public Database stateDB = new Database("state"); + public Database detaildDB = new Database("details"); public Trie worldState = new Trie(stateDB.getDb()); @@ -109,7 +111,7 @@ public class WorldManager { MainData.instance.getBlockchain().getLastBlock(); ProgramInvoke programInvoke = - ProgramInvokeFactory.createProgramInvoke(tx, lastBlock); + ProgramInvokeFactory.createProgramInvoke(tx, lastBlock, null); if (logger.isInfoEnabled()) logger.info("running the init for contract: addres={}" , @@ -128,22 +130,30 @@ public class WorldManager { Hex.toHexString( tx.getSender() ), Hex.toHexString(tx.getContractAddress()), gasDebit); worldState.update(senderAddress, senderState.getEncoded()); - VM vm = new VM(); Program program = new Program(initCode, programInvoke); vm.play(program); ProgramResult result = program.getResult(); + + // TODO: (!!!!!) ALL THE CHECKS FOR THE PROGRAM RESULT + // TODO: (!!!!!) consider introduce one method for applying results + if (result.getException() != null && + result.getException() instanceof Program.OutOfGasException){ + + // The out of gas means nothing applied + } + + + // Save the code created by init byte[] bodyCode = null; if (result.gethReturn() != null){ bodyCode = result.gethReturn().array(); } - // TODO: what if the body code is null , still submit ? - // TODO: (!!!!!) ALL THE CHECKS FOR THE PROGRAM RESULT - - BigInteger gasPrice = BigInteger.valueOf( MainData.instance.getBlockchain().getGasPrice()); + BigInteger gasPrice = + BigInteger.valueOf( MainData.instance.getBlockchain().getGasPrice()); BigInteger refund = gasDebit.subtract(BigInteger.valueOf( result.getGasUsed()).multiply(gasPrice)); @@ -168,6 +178,16 @@ public class WorldManager { Hex.toHexString(bodyCode)); } + // Save the storage changes. + Map storage = result.getStorage(); + if (storage != null){ + ContractDetails contractDetails = new ContractDetails(storage); + detaildDB.put(tx.getContractAddress() , contractDetails.getEncoded()); + } + + + + } else { if (receiverState.getCodeHash() != HashUtil.EMPTY_DATA_HASH){ @@ -178,12 +198,18 @@ public class WorldManager { Block lastBlock = MainData.instance.getBlockchain().getLastBlock(); - ProgramInvoke programInvoke = - ProgramInvokeFactory.createProgramInvoke(tx, lastBlock); - if (logger.isInfoEnabled()) logger.info("calling for existing contract: addres={}" , Hex.toHexString(tx.getReceiveAddress())); + // FETCH THE SAVED STORAGE + ContractDetails details = null; + byte[] detailsRLPData = detaildDB.get(tx.getReceiveAddress()); + if (detailsRLPData.length > 0) + details = new ContractDetails(detailsRLPData); + + ProgramInvoke programInvoke = + ProgramInvokeFactory.createProgramInvoke(tx, lastBlock, details); + VM vm = new VM(); Program program = new Program(programCode, programInvoke); vm.play(program); @@ -197,6 +223,7 @@ public class WorldManager { } } + pendingTransactions.put(Hex.toHexString(tx.getHash()), tx); } 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 59040083..75246cd4 100644 --- a/ethereumj-core/src/main/java/org/ethereum/vm/Program.java +++ b/ethereumj-core/src/main/java/org/ethereum/vm/Program.java @@ -1,5 +1,6 @@ package org.ethereum.vm; +import org.ethereum.core.ContractDetails; import org.ethereum.util.Utils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -44,6 +45,10 @@ public class Program { this.invokeData = invokeData; this.ops = ops; + + if (invokeData.getStorage() != null){ + storage = invokeData.getStorage(); + } } public byte getCurrentOp(){ @@ -415,4 +420,9 @@ public class Program { public interface ProgramListener{ public void output(String out); } + + + public class OutOfGasException extends RuntimeException{ + + } } diff --git a/ethereumj-core/src/main/java/org/ethereum/vm/ProgramInvoke.java b/ethereumj-core/src/main/java/org/ethereum/vm/ProgramInvoke.java index f84a7131..5a08342c 100644 --- a/ethereumj-core/src/main/java/org/ethereum/vm/ProgramInvoke.java +++ b/ethereumj-core/src/main/java/org/ethereum/vm/ProgramInvoke.java @@ -1,5 +1,7 @@ package org.ethereum.vm; +import java.util.Map; + /** * www.ethereumJ.com * @author: Roman Mandeleil @@ -27,4 +29,6 @@ public interface ProgramInvoke { public DataWord getDifficulty(); public DataWord getGaslimit(); + public Map getStorage(); + } diff --git a/ethereumj-core/src/main/java/org/ethereum/vm/ProgramInvokeFactory.java b/ethereumj-core/src/main/java/org/ethereum/vm/ProgramInvokeFactory.java index 92d33884..91c6ac4c 100644 --- a/ethereumj-core/src/main/java/org/ethereum/vm/ProgramInvokeFactory.java +++ b/ethereumj-core/src/main/java/org/ethereum/vm/ProgramInvokeFactory.java @@ -1,11 +1,15 @@ package org.ethereum.vm; +import org.abego.treelayout.internal.util.Contract; import org.ethereum.core.AccountState; import org.ethereum.core.Block; +import org.ethereum.core.ContractDetails; import org.ethereum.core.Transaction; import org.ethereum.manager.WorldManager; import org.ethereum.util.ByteUtil; +import java.util.Map; + /** * www.ethereumJ.com * @@ -15,15 +19,9 @@ import org.ethereum.util.ByteUtil; public class ProgramInvokeFactory { - // Invocation by the other program - public static ProgramInvoke createProgramInvoke(Program program){ - - return null; - } - // Invocation by the wire tx - public static ProgramInvoke createProgramInvoke(Transaction tx, Block lastBlock){ + public static ProgramInvoke createProgramInvoke(Transaction tx, Block lastBlock, ContractDetails details){ // https://ethereum.etherpad.mozilla.org/26 @@ -83,10 +81,14 @@ public class ProgramInvokeFactory { /*** GASLIMIT op ***/ long gaslimit = lastBlock.getGasLimit(); + /*** Map of storage values ***/ + Map storage = null; + if (details != null) + storage = details.getStorage(); ProgramInvoke programInvoke = new ProgramInvokeImpl(address, origin, caller, balance, gasPrice, gas, callValue, data, - lastHash, coinbase, timestamp, number, difficulty, gaslimit); + lastHash, coinbase, timestamp, number, difficulty, gaslimit, storage); return programInvoke; } diff --git a/ethereumj-core/src/main/java/org/ethereum/vm/ProgramInvokeImpl.java b/ethereumj-core/src/main/java/org/ethereum/vm/ProgramInvokeImpl.java index 65aa8ba5..394dd317 100644 --- a/ethereumj-core/src/main/java/org/ethereum/vm/ProgramInvokeImpl.java +++ b/ethereumj-core/src/main/java/org/ethereum/vm/ProgramInvokeImpl.java @@ -2,6 +2,8 @@ package org.ethereum.vm; import org.ethereum.util.ByteUtil; +import java.util.Map; + /** * www.ethereumJ.com * @author: Roman Mandeleil @@ -29,12 +31,12 @@ public class ProgramInvokeImpl implements ProgramInvoke { DataWord difficulty; DataWord gaslimit; - + Map storage; public ProgramInvokeImpl(byte[] address, byte[] origin, byte[] caller, byte[] balance, byte[] gasPrice, byte[] gas, byte[] callValue, byte[] msgData, byte[] lastHash, byte[] coinbase, long timestamp, long number, byte[] difficulty, - long gaslimit) { + long gaslimit, Map storage) { // Transaction env this.address = new DataWord(address); @@ -54,6 +56,7 @@ public class ProgramInvokeImpl implements ProgramInvoke { this.difficulty = new DataWord(difficulty); this.gaslimit = new DataWord(gaslimit); + this.storage = storage; } /* ADDRESS op */ @@ -171,4 +174,7 @@ public class ProgramInvokeImpl implements ProgramInvoke { public DataWord getGaslimit() { return gaslimit; } + + /* Storage */ + public Map getStorage(){ return storage; } } diff --git a/ethereumj-core/src/main/java/org/ethereum/vm/ProgramResult.java b/ethereumj-core/src/main/java/org/ethereum/vm/ProgramResult.java index fb5874db..726a8ebb 100644 --- a/ethereumj-core/src/main/java/org/ethereum/vm/ProgramResult.java +++ b/ethereumj-core/src/main/java/org/ethereum/vm/ProgramResult.java @@ -1,6 +1,8 @@ package org.ethereum.vm; import java.nio.ByteBuffer; +import java.util.HashMap; +import java.util.Map; /** * www.ethereumJ.com @@ -13,6 +15,8 @@ public class ProgramResult { private int gasUsed = 0; private ByteBuffer hReturn = null; private RuntimeException exception; + private Map storage; + public void spendGas(int gas){ gasUsed += gas; @@ -40,5 +44,11 @@ public class ProgramResult { this.exception = exception; } + public Map getStorage() { + return storage; + } + public void setStorage(Map storage) { + this.storage = storage; + } } diff --git a/ethereumj-core/src/main/java/org/ethereum/vm/VM.java b/ethereumj-core/src/main/java/org/ethereum/vm/VM.java index cf9107fc..c56105ba 100644 --- a/ethereumj-core/src/main/java/org/ethereum/vm/VM.java +++ b/ethereumj-core/src/main/java/org/ethereum/vm/VM.java @@ -567,8 +567,7 @@ public class VM { } catch (RuntimeException e) { program.setRuntimeFailure(e); } finally{ - - // todo: Here wrap the storage into result; + program.getResult().setStorage(program.storage); } } } diff --git a/ethereumj-core/src/test/java/org/ethereum/core/ContractDetailsTest.java b/ethereumj-core/src/test/java/org/ethereum/core/ContractDetailsTest.java new file mode 100644 index 00000000..d74e3bbe --- /dev/null +++ b/ethereumj-core/src/test/java/org/ethereum/core/ContractDetailsTest.java @@ -0,0 +1,90 @@ +package org.ethereum.core; + +import org.ethereum.vm.DataWord; +import org.junit.Assert; +import org.junit.Test; +import org.spongycastle.util.encoders.Hex; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +/** + * www.ethereumJ.com + * + * @author: Roman Mandeleil + * Created on: 09/06/2014 15:41 + */ + +public class ContractDetailsTest { + + @Test /* encode 2 keys/values */ + public void test1(){ + + String expected = "f888f842a00000000000000000000000000000000000000000000000000000000000000002a00000000000000000000000000000000000000000000000000000000000000001f842a00000000000000000000000000000000000000000000000000000000000009dd4a0000000000000000000000000000000000000000000000000000000000000765f"; + + DataWord key1 = new DataWord(1); + DataWord value1 = new DataWord(30303); + + DataWord key2 = new DataWord(2); + DataWord value2 = new DataWord(40404); + + + HashMap storage = new HashMap<>(); + storage.put(key1, value1); + storage.put(key2, value2); + + ContractDetails contractDetails = new ContractDetails(storage); + + String encoded = Hex.toHexString(contractDetails.getEncoded()); + + Assert.assertEquals(expected, encoded); + } + + @Test /* encode 3 keys/values */ + public void test2(){ + + String expected = "f8caf863a00000000000000000000000000000000000000000000000000000000000000002a00000000000000000000000000000000000000000000000000000000000000001a00000000000000000000000000000000000000000000000000000000000000003f863a00000000000000000000000000000000000000000000000000000000000009dd4a0000000000000000000000000000000000000000000000000000000000000765fa0000000000000000000000000000000000000000000000000000000000000ffff"; + + DataWord key1 = new DataWord(1); + DataWord value1 = new DataWord(30303); + + DataWord key2 = new DataWord(2); + DataWord value2 = new DataWord(40404); + + DataWord key3 = new DataWord(3); + DataWord value3 = new DataWord(0xFFFF); + + HashMap storage = new HashMap<>(); + storage.put(key1, value1); + storage.put(key2, value2); + storage.put(key3, value3); + + ContractDetails contractDetails = new ContractDetails(storage); + + String encoded = Hex.toHexString(contractDetails.getEncoded()); + + Assert.assertEquals(expected, encoded); + } + + @Test /* decode 3 keys/values */ + public void test3(){ + + String rlpData = "f8caf863a00000000000000000000000000000000000000000000000000000000000000002a00000000000000000000000000000000000000000000000000000000000000001a00000000000000000000000000000000000000000000000000000000000000003f863a00000000000000000000000000000000000000000000000000000000000009dd4a0000000000000000000000000000000000000000000000000000000000000765fa0000000000000000000000000000000000000000000000000000000000000ffff"; + ContractDetails contractDetails = new ContractDetails(Hex.decode(rlpData)); + + String expKey3String = "0000000000000000000000000000000000000000000000000000000000000003"; + String expVal3String = "000000000000000000000000000000000000000000000000000000000000ffff"; + + DataWord key3 = contractDetails.storageKeys.get(2); + DataWord value3 = contractDetails.storageValues.get(2); + + String key3String = Hex.toHexString(key3.getData()); + String value3String = Hex.toHexString(value3.getData()); + + Assert.assertEquals(expKey3String, key3String); + Assert.assertEquals(expVal3String, value3String); + } + + +} diff --git a/ethereumj-core/src/test/java/org/ethereum/serpent/MachineCompileTest.java b/ethereumj-core/src/test/java/org/ethereum/serpent/MachineCompileTest.java index 627ffab2..32a01737 100644 --- a/ethereumj-core/src/test/java/org/ethereum/serpent/MachineCompileTest.java +++ b/ethereumj-core/src/test/java/org/ethereum/serpent/MachineCompileTest.java @@ -45,4 +45,25 @@ public class MachineCompileTest { Assert.assertEquals(expected, result); } + @Test // contract for if jump + public void test3(){ + + String code = "a=2\n" + + "if a>0:\n" + + " b = 3\n" + + "else: \n" + + " c = 4"; +// String expected = "610100600e6000396101006000f260026000546002600054600260005460026000546002600054600260005460026000546002600054600260005460026000546002600054600260005460026000546002600054600260005460026000546002600054600260005460026000546002600054600260005460026000546002600054600260005460026000546002600054600260005460026000546002600054600260005460026000546002600054600260005460026000546002600054600260005460026000546002600054600260005460026000546002600054600260005460026000546002600054600260005460026000546002600054600260005460026000546002600054600260005469"; + String asm = SerpentCompiler.compile(code); + byte[] machineCode = SerpentCompiler.compileAssemblyToMachine(asm); + byte[] vmReadyCode = SerpentCompiler.encodeMachineCodeForVMRun(machineCode, null); + + System.out.println(asm); + System.out.println(GUIUtils.getHexStyledText(vmReadyCode)); + String result = Hex.toHexString(vmReadyCode); + +// Assert.assertEquals(expected, result); + } + + } diff --git a/ethereumj-core/src/test/java/org/ethereum/vm/ProgramInvokeMockImpl.java b/ethereumj-core/src/test/java/org/ethereum/vm/ProgramInvokeMockImpl.java index ffd8c25d..d00cb780 100644 --- a/ethereumj-core/src/test/java/org/ethereum/vm/ProgramInvokeMockImpl.java +++ b/ethereumj-core/src/test/java/org/ethereum/vm/ProgramInvokeMockImpl.java @@ -4,6 +4,8 @@ import org.ethereum.crypto.ECKey; import org.ethereum.crypto.HashUtil; import org.spongycastle.util.encoders.Hex; +import java.util.Map; + /** * www.ethereumJ.com * @author: Roman Mandeleil @@ -158,4 +160,9 @@ public class ProgramInvokeMockImpl implements ProgramInvoke { long gasLimit = 968269; return new DataWord(gasLimit); } + + @Override + public Map getStorage() { + return null; + } }