parent
115d416e78
commit
11e9190957
|
@ -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<DataWord> storageKeys;
|
||||
List<DataWord> 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<DataWord, DataWord> storage) {
|
||||
|
||||
storageKeys = new ArrayList<DataWord>();
|
||||
storageValues = new ArrayList<DataWord>();
|
||||
|
||||
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<DataWord, DataWord> getStorage(){
|
||||
|
||||
Map<DataWord, DataWord> storage = new HashMap<>();
|
||||
|
||||
for (int i = 0; i < storageKeys.size(); ++i){
|
||||
storage.put(storageKeys.get(i), storageValues.get(i));
|
||||
}
|
||||
|
||||
return storage;
|
||||
}
|
||||
}
|
|
@ -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() {
|
||||
|
|
|
@ -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);
|
||||
}}
|
||||
);
|
||||
|
||||
|
|
|
@ -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<String>();
|
||||
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);
|
||||
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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<String, Transaction> pendingTransactions =
|
||||
Collections.synchronizedMap(new HashMap<String, Transaction>());
|
||||
|
||||
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<DataWord, DataWord> 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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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{
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<DataWord, DataWord> getStorage();
|
||||
|
||||
}
|
||||
|
|
|
@ -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<DataWord, DataWord> 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;
|
||||
}
|
||||
|
|
|
@ -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<DataWord, DataWord> 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<DataWord, DataWord> 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<DataWord, DataWord> getStorage(){ return storage; }
|
||||
}
|
||||
|
|
|
@ -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<DataWord, DataWord> storage;
|
||||
|
||||
|
||||
public void spendGas(int gas){
|
||||
gasUsed += gas;
|
||||
|
@ -40,5 +44,11 @@ public class ProgramResult {
|
|||
this.exception = exception;
|
||||
}
|
||||
|
||||
public Map<DataWord, DataWord> getStorage() {
|
||||
return storage;
|
||||
}
|
||||
|
||||
public void setStorage(Map<DataWord, DataWord> storage) {
|
||||
this.storage = storage;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<DataWord, DataWord> 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<DataWord, DataWord> 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);
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -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<DataWord, DataWord> getStorage() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue