VM enhance:

+ LOG0..LOG4 implemented and tested
This commit is contained in:
romanman 2014-11-19 23:43:06 -05:00
parent 8bf61332ae
commit 23a7f75266
8 changed files with 265 additions and 9 deletions

View File

@ -10,18 +10,18 @@ public class GasCost {
/** Cost 1 gas */
public static int STEP = 1;
/** Cost 20 gas */
public static int BALANCE = 20;
/** Cost 20 gas */
public static int SHA3 = 20;
/** Cost 20 gas */
public static int SLOAD = 20;
/** Cost 0 gas */
public static int STOP = 0;
/** Cost 0 gas */
public static int SUICIDE = 0;
/** Cost 20 gas */
public static int SLOAD = 20;
/** Cost 20 gas */
public static int SHA3 = 20;
/** Cost 100 gas */
public static int SSTORE = 100;
/** Cost 20 gas */
public static int BALANCE = 20;
/** Cost 100 gas */
public static int CREATE = 100;
/** Cost 20 gas */
@ -32,4 +32,10 @@ public class GasCost {
public static int TXDATA = 5;
/** Cost 500 gas */
public static int TRANSACTION = 500;
/** Cost 32 gas */
public static int LOG_GAS = 32;
/** Cost 1 gas */
public static int LOG_DATA_GAS = 1;
/** Cost 32 gas */
public static int LOG_TOPIC_GAS = 32;
}

View File

@ -0,0 +1,60 @@
package org.ethereum.vm;
import org.spongycastle.util.encoders.Hex;
import java.util.Arrays;
import java.util.List;
/**
* www.etherj.com
*
* @author: Roman Mandeleil
* Created on: 19/11/2014 22:03
*/
public class LogInfo {
byte[] address;
List<byte[]> topics;
byte[] data;
public LogInfo(byte[] address, List<byte[]> topics, byte[] data) {
this.address = address;
this.topics = topics;
this.data = data;
}
public byte[] getAddress() {
return address;
}
public List<byte[]> getTopics() {
return topics;
}
public byte[] getData() {
return data;
}
@Override
public String toString() {
StringBuffer topicsStr = new StringBuffer();
topicsStr.append("[");
for (byte[] topic: topics){
String topicStr = Hex.toHexString(topic);
topicsStr.append(topicStr).append(" ");
}
topicsStr.append("]");
return "LogInfo{" +
"address=" + Hex.toHexString(address) +
", topics=" + topicsStr +
", data=" + Hex.toHexString(data) +
'}';
}
}

View File

@ -292,6 +292,13 @@ public enum OpCode {
/** (0x9f) Exchange 17th item from stack with the top */
SWAP16(0x9f, 17),
/** (0xa[n]) log some data for some addres with 0..n tags [addr [tag0..tagn] data] */
LOG0(0xa0, 2),
LOG1(0xa1, 3),
LOG2(0xa2, 4),
LOG3(0xa3, 5),
LOG4(0xa4, 6),
/* System operations */
/** (0xf0) Create a new account with associated code */

View File

@ -316,6 +316,7 @@ public class Program {
vm.play(program);
result = program.getResult();
this.result.addDeleteAccounts(result.getDeleteAccounts());
this.result.addLogInfos(result.getLogInfoList());
}
if (result != null &&
@ -415,6 +416,7 @@ public class Program {
result = program.getResult();
this.getProgramTrace().merge(program.getProgramTrace());
this.result.addDeleteAccounts(result.getDeleteAccounts());
this.result.addLogInfos(result.getLogInfoList());
}
if (result != null &&

View File

@ -17,6 +17,7 @@ public class ProgramResult {
private ByteBuffer hReturn = null;
private RuntimeException exception;
private List<DataWord> deleteAccounts;
private List<LogInfo> logInfoList;
private Repository repository = null;
@ -69,6 +70,20 @@ public class ProgramResult {
deleteAccounts.add(address);
}
public void addLogInfo(LogInfo logInfo){
if (this.logInfoList == null) logInfoList = new ArrayList<>();
this.logInfoList.add(logInfo);
}
public void addLogInfos(List<LogInfo> logInfos){
if (this.logInfoList == null) logInfoList = new ArrayList<>();
this.logInfoList.addAll(logInfos);
}
public List<LogInfo> getLogInfoList() {
return logInfoList;
}
public void addDeleteAccounts(List<DataWord> accounts) {
if (accounts == null) return;
if (deleteAccounts == null)

View File

@ -73,8 +73,6 @@ public class VM {
public void step(Program program) {
program.fullTrace();
if (CONFIG.vmTrace())
program.saveOpTrace();
@ -160,6 +158,16 @@ public class VM {
gasCost = GasCost.CREATE;
newMemSize = memNeeded(stack.get(stack.size()-2), stack.get(stack.size()-3));
break;
case LOG0: case LOG1: case LOG2: case LOG3: case LOG4:
int nTopics = op.val() - OpCode.LOG0.val();
newMemSize = memNeeded(stack.peek(), stack.get(stack.size()-2));
gasCost = GasCost.LOG_GAS +
GasCost.LOG_TOPIC_GAS * nTopics +
GasCost.LOG_DATA_GAS * stack.get(stack.size()-2).longValue();
break;
default:
break;
}
@ -717,6 +725,32 @@ public class VM {
stack.set(stack.size() - n, word_1);
program.step();
} break;
case LOG0: case LOG1: case LOG2: case LOG3: case LOG4:{
DataWord address = program.programAddress;
DataWord memStart = stack.pop();
DataWord memOffset = stack.pop();
int nTopics = op.val() - OpCode.LOG0.val();
List<byte[]> topics = new ArrayList<>();
for (int i = 0; i < nTopics; ++i){
DataWord topic = stack.pop();
topics.add(topic.getData());
}
ByteBuffer data = program.memoryChunk(memStart, memOffset);
LogInfo logInfo =
new LogInfo(address.getLast20Bytes(), topics, data.array());
if (logger.isInfoEnabled())
hint = logInfo.toString();
program.getResult().addLogInfo(logInfo);
} break;
case MLOAD:{
DataWord addr = program.stackPop();

View File

@ -322,4 +322,15 @@ public class ProgramMemoryTest {
program.allocateMemory(offset, size);
assertEquals(32,program.getMemSize());
}
@Test
public void testInitialInsert() {
// todo: fix the array out of bound here
int offset = 32;
int size = 00;
program.memorySave(32, 0, new byte[0]);
assertEquals(32,program.getMemSize());
}
}

View File

@ -12,6 +12,8 @@ import org.junit.Test;
import org.junit.runners.MethodSorters;
import org.spongycastle.util.encoders.Hex;
import java.util.List;
import static org.junit.Assert.*;
/**
@ -1211,6 +1213,125 @@ public class VMTest {
assertEquals(expected, Hex.toHexString(program.getMemory().array()));
}
@Test // LOG0 OP
public void tesLog0(){
VM vm = new VM();
program = new Program(Hex.decode("61123460005260206000A0"), invoke);
vm.step(program);
vm.step(program);
vm.step(program);
vm.step(program);
vm.step(program);
vm.step(program);
List<LogInfo> logInfoList = program.getResult().getLogInfoList();
LogInfo logInfo = logInfoList.get(0);
assertEquals("cd2a3d9f938e13cd947ec05abc7fe734df8dd826", Hex.toHexString(logInfo.getAddress()));
assertEquals(0, logInfo.getTopics().size());
assertEquals("0000000000000000000000000000000000000000000000000000000000001234", Hex.toHexString(logInfo.getData()));
}
@Test // LOG1 OP
public void tesLog1(){
VM vm = new VM();
program = new Program(Hex.decode("61123460005261999960206000A1"), invoke);
vm.step(program);
vm.step(program);
vm.step(program);
vm.step(program);
vm.step(program);
vm.step(program);
vm.step(program);
List<LogInfo> logInfoList = program.getResult().getLogInfoList();
LogInfo logInfo = logInfoList.get(0);
assertEquals("cd2a3d9f938e13cd947ec05abc7fe734df8dd826", Hex.toHexString(logInfo.getAddress()));
assertEquals(1, logInfo.getTopics().size());
assertEquals("0000000000000000000000000000000000000000000000000000000000001234", Hex.toHexString(logInfo.getData()));
}
@Test // LOG2 OP
public void tesLog2(){
VM vm = new VM();
program = new Program(Hex.decode("61123460005261999961666660206000A2"), invoke);
vm.step(program);
vm.step(program);
vm.step(program);
vm.step(program);
vm.step(program);
vm.step(program);
vm.step(program);
vm.step(program);
List<LogInfo> logInfoList = program.getResult().getLogInfoList();
LogInfo logInfo = logInfoList.get(0);
assertEquals("cd2a3d9f938e13cd947ec05abc7fe734df8dd826", Hex.toHexString(logInfo.getAddress()));
assertEquals(2, logInfo.getTopics().size());
assertEquals("0000000000000000000000000000000000000000000000000000000000001234", Hex.toHexString(logInfo.getData()));
}
@Test // LOG3 OP
public void tesLog3(){
VM vm = new VM();
program = new Program(Hex.decode("61123460005261999961666661333360206000A3"), invoke);
vm.step(program);
vm.step(program);
vm.step(program);
vm.step(program);
vm.step(program);
vm.step(program);
vm.step(program);
vm.step(program);
vm.step(program);
List<LogInfo> logInfoList = program.getResult().getLogInfoList();
LogInfo logInfo = logInfoList.get(0);
assertEquals("cd2a3d9f938e13cd947ec05abc7fe734df8dd826", Hex.toHexString(logInfo.getAddress()));
assertEquals(3, logInfo.getTopics().size());
assertEquals("0000000000000000000000000000000000000000000000000000000000001234", Hex.toHexString(logInfo.getData()));
}
@Test // LOG4 OP
public void tesLog4(){
VM vm = new VM();
program = new Program(Hex.decode("61123460005261999961666661333361555560206000A4"), invoke);
vm.step(program);
vm.step(program);
vm.step(program);
vm.step(program);
vm.step(program);
vm.step(program);
vm.step(program);
vm.step(program);
vm.step(program);
vm.step(program);
List<LogInfo> logInfoList = program.getResult().getLogInfoList();
LogInfo logInfo = logInfoList.get(0);
assertEquals("cd2a3d9f938e13cd947ec05abc7fe734df8dd826", Hex.toHexString(logInfo.getAddress()));
assertEquals(4, logInfo.getTopics().size());
assertEquals("0000000000000000000000000000000000000000000000000000000000001234", Hex.toHexString(logInfo.getData()));
}
@Test // MSTORE OP
public void testMSTORE_2() {