CALL with data in:
+ ProgramPlayDialog adjust for simple code play (stand alone run) + msg - compile fixed to generated the right code + VMComplexTest to test contractA --> ContractB with data [11, 22]
This commit is contained in:
parent
6ef4365a6d
commit
7fbd2964b5
|
@ -5,11 +5,9 @@ import org.ethereum.core.ContractDetails;
|
|||
import org.ethereum.core.Transaction;
|
||||
import org.ethereum.db.TrackDatabase;
|
||||
import org.ethereum.manager.WorldManager;
|
||||
import org.ethereum.serpent.SerpentCompiler;
|
||||
import org.ethereum.trie.TrackTrie;
|
||||
import org.ethereum.vm.Program;
|
||||
import org.ethereum.vm.ProgramInvokeFactory;
|
||||
import org.ethereum.vm.ProgramInvokeImpl;
|
||||
import org.ethereum.vm.VM;
|
||||
import org.ethereum.vm.*;
|
||||
import org.spongycastle.util.encoders.Hex;
|
||||
|
||||
import javax.swing.*;
|
||||
|
@ -36,6 +34,24 @@ public class ProgramPlayDialog extends JPanel implements ActionListener,
|
|||
|
||||
private Transaction tx;
|
||||
|
||||
public ProgramPlayDialog(byte[] code){
|
||||
|
||||
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, ContractDetails contractDetails) {
|
||||
|
||||
this.tx = tx;
|
||||
|
@ -60,6 +76,10 @@ public class ProgramPlayDialog extends JPanel implements ActionListener,
|
|||
trackStateDB.rollbackTrack();
|
||||
|
||||
|
||||
doGUI();
|
||||
}
|
||||
|
||||
public void doGUI(){
|
||||
setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS));
|
||||
|
||||
//Create the slider.
|
||||
|
@ -137,7 +157,12 @@ public class ProgramPlayDialog extends JPanel implements ActionListener,
|
|||
*/
|
||||
public static void createAndShowGUI(byte[] runCode, Transaction tx, Block lastBlock, ContractDetails details) {
|
||||
|
||||
ProgramPlayDialog ppd = new ProgramPlayDialog(runCode, tx, lastBlock, details);
|
||||
ProgramPlayDialog ppd;
|
||||
if (tx != null)
|
||||
ppd = new ProgramPlayDialog(runCode, tx, lastBlock, details);
|
||||
else{
|
||||
ppd = new ProgramPlayDialog(runCode);
|
||||
}
|
||||
|
||||
//Create and set up the window.
|
||||
JFrame frame = new JFrame("Program Draft Play");
|
||||
|
@ -173,13 +198,15 @@ public class ProgramPlayDialog extends JPanel implements ActionListener,
|
|||
//Schedule a job for the event-dispatching thread:
|
||||
//creating and showing this application's GUI.
|
||||
|
||||
/* todo: make dummy tx for dialog single invokation
|
||||
String asmCode ="0 31 MSTORE8 224 MSIZE 224 MSIZE MSTORE 0 192 MSIZE ADD MSTORE8 96 MSIZE 32 ADD MSIZE DUP 32 ADD 11 SWAP MSTORE DUP 64 ADD 22 SWAP MSTORE DUP 96 ADD 33 SWAP MSTORE 128 SWAP MSTORE 0 752278364205682983151548199104072833112320979438 1000 CALL 32 0 MUL 160 ADD 32 ADD MLOAD 0 MSTORE";
|
||||
final byte[] code = SerpentCompiler.compileAssemblyToMachine(asmCode);
|
||||
|
||||
|
||||
SwingUtilities.invokeLater(new Runnable() {
|
||||
public void run() {
|
||||
createAndShowGUI();
|
||||
createAndShowGUI(code, null, null, null);
|
||||
}
|
||||
});
|
||||
*/
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -204,18 +204,7 @@ public class SerpentToAssemblyCompiler extends SerpentBaseVisitor<String> {
|
|||
// msg assigned has two arrays to calc
|
||||
if (ctx.msg_func() != null){
|
||||
|
||||
String msgCode = visitMsg_func(ctx.msg_func());
|
||||
int outSize = getMsgOutputArraySize(msgCode);
|
||||
int inSize = getMsgInputArraySize(msgCode);
|
||||
msgCode = cleanMsgString(msgCode);
|
||||
|
||||
String randomArrayName = new String(HashUtil.randomPeerId());
|
||||
arraysSize.put(randomArrayName, inSize * 32 + 32);
|
||||
arraysIndex.add(randomArrayName);
|
||||
|
||||
arraysSize.put(varName, outSize * 32 + 32);
|
||||
arraysIndex.add(varName);
|
||||
|
||||
String msgCode = visitMsg_func(ctx.msg_func(), varName);
|
||||
return msgCode;
|
||||
} else if (ctx.arr_def() != null){
|
||||
// if it's an array the all management is different
|
||||
|
@ -599,22 +588,46 @@ public class SerpentToAssemblyCompiler extends SerpentBaseVisitor<String> {
|
|||
return String.format("%s 32 MUL CALLDATALOAD ", operand0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String visitMsg_func(@NotNull SerpentParser.Msg_funcContext ctx) {
|
||||
public String visitMsg_func(@NotNull SerpentParser.Msg_funcContext ctx, String varName) {
|
||||
|
||||
// msg_func: 'msg' '(' int_val ',' int_val ',' int_val ',' arr_def ',' int_val ',' int_val')' ;
|
||||
// msg_func: 'msg' '(' [gas] ',' [to] ',' [value] ',' arr_def ',' [in_len] ',' [out_len]')' ;
|
||||
|
||||
String operand0 = visit(ctx.int_val(0));
|
||||
String operand1 = visit(ctx.int_val(1));
|
||||
String operand2 = visit(ctx.int_val(2));
|
||||
String operand3 = visit(ctx.arr_def());
|
||||
String operand4 = visit(ctx.int_val(3));
|
||||
String operand5 = visit(ctx.int_val(4));
|
||||
String operand0 = visit(ctx.int_val(0));
|
||||
String operand1 = visit(ctx.int_val(1));
|
||||
String operand2 = visit(ctx.int_val(2));
|
||||
|
||||
// OUTDATASIZE OUTDATASTART INDATASIZE INDATASTART VALUE TO GAS CALL
|
||||
return String.format("<out_size %s out_size> <in_size %s in_size> %s %s %s %s %s %s CALL ",
|
||||
operand5, operand4, operand5, operand4, operand3, operand2, operand1, operand0);
|
||||
String loadInData = visit(ctx.arr_def());
|
||||
|
||||
String inSizeCallParam = visit(ctx.int_val(3));
|
||||
String outSizeCallParam = visit(ctx.int_val(4));
|
||||
|
||||
// todo: 1. allocate out_memory and push ptr
|
||||
// todo: 2. push ptr for in_memory allocated
|
||||
|
||||
String randomArrayName = new String(HashUtil.randomPeerId());
|
||||
|
||||
int inSize = Integer.parseInt( inSizeCallParam );
|
||||
int outSize = Integer.parseInt( outSizeCallParam );
|
||||
|
||||
arraysSize.put(randomArrayName, inSize * 32 + 32);
|
||||
arraysIndex.add(randomArrayName);
|
||||
|
||||
int outSizeVal = outSize * 32 + 32;
|
||||
arraysSize.put(varName, outSize * 32 + 32);
|
||||
arraysIndex.add(varName);
|
||||
|
||||
|
||||
// [OUTDATASIZE] [OUTDATASTART] [INDATASIZE] [INDATASTART] [VALUE] [TO] [GAS] CALL
|
||||
// [OUTDATASIZE] [OUTDATASTART] [INDATASIZE] [INDATASTART] ***ARR_IN_SET*** [VALUE] [TO] [GAS] CALL
|
||||
//X_X = [ 32 + 128 + 6 * 32 ] = [ var_table_size + in_arr_size + out_arr_size ]
|
||||
|
||||
// this code allocates the memory block for the out data,
|
||||
// and saves the size in typical array format [size, element_1, element_2, ...]
|
||||
String outArrSet = String.format( " %d MSIZE MSTORE 0 %d MSIZE ADD MSTORE8 ", outSizeVal, outSizeVal - 32 );
|
||||
|
||||
return String.format("%d MSIZE %s %d %s %s %s %s CALL ",
|
||||
outSizeVal, outArrSet ,inSize * 32, loadInData, operand2, operand1, operand0);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -685,8 +698,6 @@ public class SerpentToAssemblyCompiler extends SerpentBaseVisitor<String> {
|
|||
return (new BigInteger(1, numberBytes)).toString();
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static class UnknownOperandException extends RuntimeException {
|
||||
public UnknownOperandException(String name) {
|
||||
super("unknown operand: " + name);
|
||||
|
@ -739,7 +750,10 @@ public class SerpentToAssemblyCompiler extends SerpentBaseVisitor<String> {
|
|||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* After the array deff code is set
|
||||
* extract the size out of code string
|
||||
*/
|
||||
private Integer getArraySize(String code){
|
||||
|
||||
String result = "0";
|
||||
|
|
|
@ -244,7 +244,7 @@ public class Program {
|
|||
|
||||
AccountState receiverState;
|
||||
byte[] accountData = result.getStateDb().get(toAddress);
|
||||
if (accountData == null){
|
||||
if (accountData == null || accountData.length == 0){
|
||||
|
||||
logger.info("no saved address in db to call: address={}" ,Hex.toHexString(toAddress));
|
||||
return;
|
||||
|
|
|
@ -26,6 +26,7 @@ public class ProgramInvokeMockImpl implements ProgramInvoke {
|
|||
|
||||
ContractDetails details = null;
|
||||
|
||||
String ownerAddress;
|
||||
|
||||
|
||||
public ProgramInvokeMockImpl(byte[] msgDataRaw){
|
||||
|
@ -38,7 +39,7 @@ public class ProgramInvokeMockImpl implements ProgramInvoke {
|
|||
/* ADDRESS op */
|
||||
public DataWord getOwnerAddress(){
|
||||
|
||||
byte[] addr = Hex.decode("77045e71a7a2c50903d88e564cd72fab11e82051");
|
||||
byte[] addr = Hex.decode(ownerAddress);
|
||||
return new DataWord(addr);
|
||||
}
|
||||
|
||||
|
@ -187,6 +188,11 @@ public class ProgramInvokeMockImpl implements ProgramInvoke {
|
|||
this.details = details;
|
||||
}
|
||||
|
||||
public void setOwnerAddress(String ownerAddress) {
|
||||
this.ownerAddress = ownerAddress;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Map<DataWord, DataWord> getStorage() {
|
||||
if (details == null) return null;
|
|
@ -1329,7 +1329,7 @@ public class SerpentCompileTest {
|
|||
String code = "\n" +
|
||||
"a = msg(1, 2, 3, [11, 22, 33], 3, 6) \n" +
|
||||
"b = a[0]\n" ;
|
||||
String expected = "0 31 MSTORE8 6 3 MSIZE 32 ADD MSIZE DUP 32 ADD 11 SWAP MSTORE DUP 64 ADD 22 SWAP MSTORE DUP 96 ADD 33 SWAP MSTORE 128 SWAP MSTORE 3 2 1 CALL 32 0 MUL 160 ADD 32 ADD MLOAD 0 MSTORE";
|
||||
String expected = "0 31 MSTORE8 MSIZE 32 ADD MSIZE DUP 32 ADD 11 SWAP MSTORE DUP 64 ADD 22 SWAP MSTORE DUP 96 ADD 33 SWAP MSTORE 128 SWAP MSTORE 6 3 3 2 1 CALL 32 0 MUL 160 ADD 32 ADD MLOAD 0 MSTORE";
|
||||
|
||||
String asmResult = SerpentCompiler.compile(code);
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package org.ethereum.vm;
|
||||
|
||||
import org.abego.treelayout.internal.util.Contract;
|
||||
import org.ethereum.core.AccountState;
|
||||
import org.ethereum.core.ContractDetails;
|
||||
import org.ethereum.crypto.HashUtil;
|
||||
|
@ -82,6 +83,8 @@ public class VMComplexTest {
|
|||
pi.setChainDb(chainDb);
|
||||
pi.setStateDB(stateDB);
|
||||
pi.setDetails(contractDetails);
|
||||
pi.setOwnerAddress("77045e71a7a2c50903d88e564cd72fab11e82051");
|
||||
|
||||
|
||||
// Play the program
|
||||
VM vm = new VM();
|
||||
|
@ -104,10 +107,119 @@ public class VMComplexTest {
|
|||
System.out.println("*** Used gas: " + program.result.getGasUsed());
|
||||
System.out.println("*** Contract Balance: " + as.getBalance());
|
||||
|
||||
// todo: assert caller balance after contract exec
|
||||
|
||||
assertEquals(expectedGas, program.result.getGasUsed());
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Test // contract call recursive with data
|
||||
public void test2(){
|
||||
|
||||
/**
|
||||
* #The code will run
|
||||
* ------------------
|
||||
|
||||
contract A: 77045e71a7a2c50903d88e564cd72fab11e82051
|
||||
---------------
|
||||
a = msg.data[0]
|
||||
b = msg.data[1]
|
||||
|
||||
contract.storage[a]
|
||||
contract.storage[b]
|
||||
|
||||
|
||||
contract B: 83c5541a6c8d2dbad642f385d8d06ca9b6c731ee
|
||||
-----------
|
||||
a = msg((tx.gas / 10 * 8), 0x77045e71a7a2c50903d88e564cd72fab11e82051, 0, [11, 22, 33], 3, 6)
|
||||
|
||||
*/
|
||||
|
||||
|
||||
long expectedVal_1 = 11;
|
||||
long expectedVal_2 = 22;
|
||||
|
||||
// Set contract into Database
|
||||
String callerAddr = "cd2a3d9f938e13cd947ec05abc7fe734df8dd826";
|
||||
|
||||
String contractA_addr = "77045e71a7a2c50903d88e564cd72fab11e82051";
|
||||
String contractB_addr = "83c5541a6c8d2dbad642f385d8d06ca9b6c731ee";
|
||||
|
||||
String code_a = "60006020023560005460016020023560205460005360005760205360015700";
|
||||
String code_b = "6000601f5560e05b60e05b54600060c05b015560605b6020015b51602001600b5254516040016016525451606001602152546080525460007377045e71a7a2c50903d88e564cd72fab11e820516103e8f1602060000260a00160200153600054";
|
||||
|
||||
byte[] caller_addr_bytes = Hex.decode(callerAddr);
|
||||
|
||||
byte[] contractA_addr_bytes = Hex.decode(contractA_addr);
|
||||
byte[] codeA = Hex.decode(code_a);
|
||||
byte[] codeA_Key = HashUtil.sha3(codeA);
|
||||
AccountState accountState_a = new AccountState();
|
||||
accountState_a.setCodeHash(codeA_Key);
|
||||
WorldManager.instance.worldState.update(contractA_addr_bytes, accountState_a.getEncoded());
|
||||
|
||||
byte[] contractB_addr_bytes = Hex.decode(contractB_addr);
|
||||
byte[] codeB = Hex.decode(code_b);
|
||||
byte[] codeB_Key = HashUtil.sha3(codeB);
|
||||
AccountState accountState_b = new AccountState();
|
||||
accountState_b.setCodeHash(codeB_Key);
|
||||
WorldManager.instance.worldState.update(contractB_addr_bytes, accountState_a.getEncoded());
|
||||
|
||||
AccountState callerAcountState = new AccountState();
|
||||
callerAcountState.addToBalance(new BigInteger("100000000000000000000"));
|
||||
WorldManager.instance.worldState.update(caller_addr_bytes, callerAcountState.getEncoded());
|
||||
|
||||
WorldManager.instance.chainDB.put(codeA_Key, codeA);
|
||||
|
||||
TrackTrie stateDB = new TrackTrie(WorldManager.instance.worldState);
|
||||
TrackDatabase chainDb = new TrackDatabase(WorldManager.instance.chainDB);
|
||||
TrackDatabase detaildDB = new TrackDatabase(WorldManager.instance.detaildDB);
|
||||
|
||||
ProgramInvokeMockImpl pi = new ProgramInvokeMockImpl();
|
||||
pi.setDetaildDB(detaildDB);
|
||||
pi.setChainDb(chainDb);
|
||||
pi.setStateDB(stateDB);
|
||||
pi.setDetails(null);
|
||||
pi.setOwnerAddress(contractB_addr);
|
||||
|
||||
// ****************** //
|
||||
// Play the program //
|
||||
// ****************** //
|
||||
VM vm = new VM();
|
||||
Program program = new Program(codeB, pi);
|
||||
|
||||
try {
|
||||
while(!program.isStopped())
|
||||
vm.step(program);
|
||||
} catch (RuntimeException e) {
|
||||
program.setRuntimeFailure(e);
|
||||
}
|
||||
|
||||
|
||||
System.out.println();
|
||||
System.out.println("============ Results ============");
|
||||
AccountState as =
|
||||
new AccountState(WorldManager.instance.worldState.get(
|
||||
Hex.decode( contractA_addr) ));
|
||||
|
||||
|
||||
System.out.println("*** Used gas: " + program.result.getGasUsed());
|
||||
|
||||
|
||||
byte[] rlpBytes = WorldManager.instance.detaildDB.get(contractA_addr_bytes);
|
||||
|
||||
ContractDetails details = new ContractDetails(rlpBytes);
|
||||
DataWord value_1 = details.getStorage().get(new DataWord(00));
|
||||
DataWord value_2 = details.getStorage().get(new DataWord(01));
|
||||
|
||||
|
||||
assertEquals(expectedVal_1, value_1.longValue());
|
||||
assertEquals(expectedVal_2, value_2.longValue());
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue