vmIOandFlowOperationsTest
This commit is contained in:
parent
7c0a6fb65d
commit
da9fc3d391
|
@ -55,13 +55,21 @@ public class TestCase {
|
||||||
JSONObject envJSON = (JSONObject)testCaseJSONObj.get("env");
|
JSONObject envJSON = (JSONObject)testCaseJSONObj.get("env");
|
||||||
JSONObject execJSON = (JSONObject)testCaseJSONObj.get("exec");
|
JSONObject execJSON = (JSONObject)testCaseJSONObj.get("exec");
|
||||||
JSONObject preJSON = (JSONObject)testCaseJSONObj.get("pre");
|
JSONObject preJSON = (JSONObject)testCaseJSONObj.get("pre");
|
||||||
JSONObject postJSON = (JSONObject)testCaseJSONObj.get("post");
|
JSONObject postJSON = new JSONObject();
|
||||||
JSONArray callCreates = (JSONArray)testCaseJSONObj.get("callcreates");
|
if(testCaseJSONObj.containsKey("post")) // in cases where there is no post dictionary (when testing for exceptions for example)
|
||||||
|
postJSON = (JSONObject)testCaseJSONObj.get("post");
|
||||||
|
JSONArray callCreates = new JSONArray();
|
||||||
|
if(testCaseJSONObj.containsKey("callcreates"))
|
||||||
|
callCreates = (JSONArray)testCaseJSONObj.get("callcreates");
|
||||||
|
|
||||||
String gasString = testCaseJSONObj.get("gas").toString();
|
String gasString = "0";
|
||||||
|
if(testCaseJSONObj.containsKey("gas"))
|
||||||
|
gasString = testCaseJSONObj.get("gas").toString();
|
||||||
this.gas = ByteUtil.bigIntegerToBytes(new BigInteger(gasString));
|
this.gas = ByteUtil.bigIntegerToBytes(new BigInteger(gasString));
|
||||||
|
|
||||||
String outString = testCaseJSONObj.get("out").toString();
|
String outString = null;
|
||||||
|
if(testCaseJSONObj.containsKey("out"))
|
||||||
|
outString = testCaseJSONObj.get("out").toString();
|
||||||
if (outString != null && outString.length() > 2)
|
if (outString != null && outString.length() > 2)
|
||||||
this.out = Hex.decode(outString.substring(2));
|
this.out = Hex.decode(outString.substring(2));
|
||||||
else
|
else
|
||||||
|
|
|
@ -99,218 +99,249 @@ public class TestRunner {
|
||||||
/* 4. run VM */
|
/* 4. run VM */
|
||||||
VM vm = new VM();
|
VM vm = new VM();
|
||||||
Program program = new Program(exec.getCode(), programInvoke);
|
Program program = new Program(exec.getCode(), programInvoke);
|
||||||
while(!program.isStopped())
|
boolean vmDidThrowAnEception = false;
|
||||||
vm.step(program);
|
RuntimeException e = null;
|
||||||
|
try {
|
||||||
|
while(!program.isStopped())
|
||||||
|
vm.step(program);
|
||||||
|
}
|
||||||
|
catch (RuntimeException ex) {
|
||||||
|
vmDidThrowAnEception = true;
|
||||||
|
e = ex;
|
||||||
|
}
|
||||||
program.saveProgramTraceToFile(testCase.getName());
|
program.saveProgramTraceToFile(testCase.getName());
|
||||||
|
|
||||||
this.trace = program.getProgramTrace();
|
if(testCase.getPost().size() == 0) {
|
||||||
|
if(vmDidThrowAnEception != true) {
|
||||||
|
String output =
|
||||||
|
String.format("VM was expected to throw an exception");
|
||||||
|
logger.info(output);
|
||||||
|
results.add(output);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
logger.info("VM did throw an exception: " + e.toString());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if(vmDidThrowAnEception) {
|
||||||
|
String output =
|
||||||
|
String.format("VM threw an unexpected exception: " + e.toString());
|
||||||
|
logger.info(output);
|
||||||
|
results.add(output);
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
System.out.println("--------- POST --------");
|
this.trace = program.getProgramTrace();
|
||||||
/* 5. Assert Post values */
|
|
||||||
for (ByteArrayWrapper key : testCase.getPost().keySet()) {
|
|
||||||
|
|
||||||
AccountState accountState = testCase.getPost().get(key);
|
System.out.println("--------- POST --------");
|
||||||
|
/* 5. Assert Post values */
|
||||||
|
for (ByteArrayWrapper key : testCase.getPost().keySet()) {
|
||||||
|
|
||||||
long expectedNonce = accountState.getNonceLong();
|
AccountState accountState = testCase.getPost().get(key);
|
||||||
BigInteger expectedBalance = accountState.getBigIntegerBalance();
|
|
||||||
byte[] expectedCode = accountState.getCode();
|
|
||||||
|
|
||||||
boolean accountExist = (null != repository.getAccountState(key.getData()));
|
long expectedNonce = accountState.getNonceLong();
|
||||||
if (!accountExist) {
|
BigInteger expectedBalance = accountState.getBigIntegerBalance();
|
||||||
|
byte[] expectedCode = accountState.getCode();
|
||||||
|
|
||||||
String output =
|
boolean accountExist = (null != repository.getAccountState(key.getData()));
|
||||||
String.format("The expected account does not exist. key: [ %s ]",
|
if (!accountExist) {
|
||||||
Hex.toHexString(key.getData()));
|
|
||||||
logger.info(output);
|
|
||||||
results.add(output);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
long actualNonce = repository.getNonce(key.getData()).longValue();
|
String output =
|
||||||
BigInteger actualBalance = repository.getBalance(key.getData());
|
String.format("The expected account does not exist. key: [ %s ]",
|
||||||
byte[] actualCode = repository.getCode(key.getData());
|
Hex.toHexString(key.getData()));
|
||||||
if (actualCode == null) actualCode = "".getBytes();
|
logger.info(output);
|
||||||
|
results.add(output);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (expectedNonce != actualNonce) {
|
long actualNonce = repository.getNonce(key.getData()).longValue();
|
||||||
|
BigInteger actualBalance = repository.getBalance(key.getData());
|
||||||
|
byte[] actualCode = repository.getCode(key.getData());
|
||||||
|
if (actualCode == null) actualCode = "".getBytes();
|
||||||
|
|
||||||
String output =
|
if (expectedNonce != actualNonce) {
|
||||||
String.format("The nonce result is different. key: [ %s ], expectedNonce: [ %d ] is actualNonce: [ %d ] ",
|
|
||||||
Hex.toHexString(key.getData()), expectedNonce, actualNonce);
|
|
||||||
logger.info(output);
|
|
||||||
results.add(output);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!expectedBalance.equals(actualBalance)) {
|
String output =
|
||||||
|
String.format("The nonce result is different. key: [ %s ], expectedNonce: [ %d ] is actualNonce: [ %d ] ",
|
||||||
|
Hex.toHexString(key.getData()), expectedNonce, actualNonce);
|
||||||
|
logger.info(output);
|
||||||
|
results.add(output);
|
||||||
|
}
|
||||||
|
|
||||||
String output =
|
if (!expectedBalance.equals(actualBalance)) {
|
||||||
String.format("The balance result is different. key: [ %s ], expectedBalance: [ %s ] is actualBalance: [ %s ] ",
|
|
||||||
Hex.toHexString(key.getData()), expectedBalance.toString(), actualBalance.toString());
|
|
||||||
logger.info(output);
|
|
||||||
results.add(output);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!Arrays.equals(expectedCode, actualCode)) {
|
String output =
|
||||||
|
String.format("The balance result is different. key: [ %s ], expectedBalance: [ %s ] is actualBalance: [ %s ] ",
|
||||||
|
Hex.toHexString(key.getData()), expectedBalance.toString(), actualBalance.toString());
|
||||||
|
logger.info(output);
|
||||||
|
results.add(output);
|
||||||
|
}
|
||||||
|
|
||||||
String output =
|
if (!Arrays.equals(expectedCode, actualCode)) {
|
||||||
String.format("The code result is different. account: [ %s ], expectedCode: [ %s ] is actualCode: [ %s ] ",
|
|
||||||
Hex.toHexString(key.getData()),
|
|
||||||
Hex.toHexString(expectedCode),
|
|
||||||
Hex.toHexString(actualCode));
|
|
||||||
logger.info(output);
|
|
||||||
results.add(output);
|
|
||||||
}
|
|
||||||
|
|
||||||
// assert storage
|
String output =
|
||||||
Map<ByteArrayWrapper, ByteArrayWrapper> storage = accountState.getStorage();
|
String.format("The code result is different. account: [ %s ], expectedCode: [ %s ] is actualCode: [ %s ] ",
|
||||||
for (ByteArrayWrapper storageKey : storage.keySet()) {
|
Hex.toHexString(key.getData()),
|
||||||
|
Hex.toHexString(expectedCode),
|
||||||
|
Hex.toHexString(actualCode));
|
||||||
|
logger.info(output);
|
||||||
|
results.add(output);
|
||||||
|
}
|
||||||
|
|
||||||
byte[] expectedStValue = storage.get(storageKey).getData();
|
// assert storage
|
||||||
|
Map<ByteArrayWrapper, ByteArrayWrapper> storage = accountState.getStorage();
|
||||||
|
for (ByteArrayWrapper storageKey : storage.keySet()) {
|
||||||
|
|
||||||
ContractDetails contractDetails =
|
byte[] expectedStValue = storage.get(storageKey).getData();
|
||||||
program.getResult().getRepository().getContractDetails(accountState.getAddress());
|
|
||||||
|
|
||||||
if (contractDetails == null) {
|
ContractDetails contractDetails =
|
||||||
|
program.getResult().getRepository().getContractDetails(accountState.getAddress());
|
||||||
|
|
||||||
String output =
|
if (contractDetails == null) {
|
||||||
String.format("Storage raw doesn't exist: key [ %s ], expectedValue: [ %s ]",
|
|
||||||
Hex.toHexString(storageKey.getData()),
|
|
||||||
Hex.toHexString(expectedStValue)
|
|
||||||
);
|
|
||||||
logger.info(output);
|
|
||||||
results.add(output);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
Map<DataWord, DataWord> testStorage = contractDetails.getStorage();
|
String output =
|
||||||
DataWord actualValue = testStorage.get(new DataWord(storageKey.getData()));
|
String.format("Storage raw doesn't exist: key [ %s ], expectedValue: [ %s ]",
|
||||||
|
Hex.toHexString(storageKey.getData()),
|
||||||
|
Hex.toHexString(expectedStValue)
|
||||||
|
);
|
||||||
|
logger.info(output);
|
||||||
|
results.add(output);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (actualValue == null ||
|
Map<DataWord, DataWord> testStorage = contractDetails.getStorage();
|
||||||
!Arrays.equals(expectedStValue, actualValue.getNoLeadZeroesData())) {
|
DataWord actualValue = testStorage.get(new DataWord(storageKey.getData()));
|
||||||
|
|
||||||
String output =
|
if (actualValue == null ||
|
||||||
String.format("Storage value different: key [ %s ], expectedValue: [ %s ], actualValue: [ %s ]",
|
!Arrays.equals(expectedStValue, actualValue.getNoLeadZeroesData())) {
|
||||||
Hex.toHexString(storageKey.getData()),
|
|
||||||
Hex.toHexString(expectedStValue),
|
|
||||||
actualValue == null ? "" : Hex.toHexString(actualValue.getNoLeadZeroesData()));
|
|
||||||
logger.info(output);
|
|
||||||
results.add(output);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: assert that you have no extra accounts in the repository
|
String output =
|
||||||
// TODO: -> basically the deleted by suicide should be deleted
|
String.format("Storage value different: key [ %s ], expectedValue: [ %s ], actualValue: [ %s ]",
|
||||||
// TODO: -> and no unexpected created
|
Hex.toHexString(storageKey.getData()),
|
||||||
|
Hex.toHexString(expectedStValue),
|
||||||
|
actualValue == null ? "" : Hex.toHexString(actualValue.getNoLeadZeroesData()));
|
||||||
|
logger.info(output);
|
||||||
|
results.add(output);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
List<org.ethereum.vm.CallCreate> resultCallCreates =
|
// TODO: assert that you have no extra accounts in the repository
|
||||||
program.getResult().getCallCreateList();
|
// TODO: -> basically the deleted by suicide should be deleted
|
||||||
|
// TODO: -> and no unexpected created
|
||||||
|
|
||||||
// assert call creates
|
List<org.ethereum.vm.CallCreate> resultCallCreates =
|
||||||
for (int i = 0; i < testCase.getCallCreateList().size(); ++i) {
|
program.getResult().getCallCreateList();
|
||||||
|
|
||||||
org.ethereum.vm.CallCreate resultCallCreate = null;
|
// assert call creates
|
||||||
if (resultCallCreates != null && resultCallCreates.size() > i) {
|
for (int i = 0; i < testCase.getCallCreateList().size(); ++i) {
|
||||||
resultCallCreate = resultCallCreates.get(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
CallCreate expectedCallCreate = testCase.getCallCreateList().get(i);
|
org.ethereum.vm.CallCreate resultCallCreate = null;
|
||||||
|
if (resultCallCreates != null && resultCallCreates.size() > i) {
|
||||||
|
resultCallCreate = resultCallCreates.get(i);
|
||||||
|
}
|
||||||
|
|
||||||
if (resultCallCreate == null && expectedCallCreate != null) {
|
CallCreate expectedCallCreate = testCase.getCallCreateList().get(i);
|
||||||
|
|
||||||
String output =
|
if (resultCallCreate == null && expectedCallCreate != null) {
|
||||||
String.format("Missing call/create invoke: to: [ %s ], data: [ %s ], gas: [ %s ], value: [ %s ]",
|
|
||||||
Hex.toHexString(expectedCallCreate.getDestination()),
|
|
||||||
Hex.toHexString(expectedCallCreate.getData()),
|
|
||||||
Hex.toHexString(expectedCallCreate.getGasLimit()),
|
|
||||||
Hex.toHexString(expectedCallCreate.getValue()));
|
|
||||||
logger.info(output);
|
|
||||||
results.add(output);
|
|
||||||
|
|
||||||
continue;
|
String output =
|
||||||
}
|
String.format("Missing call/create invoke: to: [ %s ], data: [ %s ], gas: [ %s ], value: [ %s ]",
|
||||||
|
Hex.toHexString(expectedCallCreate.getDestination()),
|
||||||
|
Hex.toHexString(expectedCallCreate.getData()),
|
||||||
|
Hex.toHexString(expectedCallCreate.getGasLimit()),
|
||||||
|
Hex.toHexString(expectedCallCreate.getValue()));
|
||||||
|
logger.info(output);
|
||||||
|
results.add(output);
|
||||||
|
|
||||||
boolean assertDestination = Arrays.equals(
|
continue;
|
||||||
expectedCallCreate.getDestination(),
|
}
|
||||||
resultCallCreate.getDestination());
|
|
||||||
if (!assertDestination) {
|
|
||||||
|
|
||||||
String output =
|
boolean assertDestination = Arrays.equals(
|
||||||
String.format("Call/Create destination is different. Expected: [ %s ], result: [ %s ]",
|
expectedCallCreate.getDestination(),
|
||||||
Hex.toHexString(expectedCallCreate.getDestination()),
|
resultCallCreate.getDestination());
|
||||||
Hex.toHexString(resultCallCreate.getDestination()));
|
if (!assertDestination) {
|
||||||
logger.info(output);
|
|
||||||
results.add(output);
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean assertData = Arrays.equals(
|
String output =
|
||||||
expectedCallCreate.getData(),
|
String.format("Call/Create destination is different. Expected: [ %s ], result: [ %s ]",
|
||||||
resultCallCreate.getData());
|
Hex.toHexString(expectedCallCreate.getDestination()),
|
||||||
if (!assertData) {
|
Hex.toHexString(resultCallCreate.getDestination()));
|
||||||
|
logger.info(output);
|
||||||
|
results.add(output);
|
||||||
|
}
|
||||||
|
|
||||||
String output =
|
boolean assertData = Arrays.equals(
|
||||||
String.format("Call/Create data is different. Expected: [ %s ], result: [ %s ]",
|
expectedCallCreate.getData(),
|
||||||
Hex.toHexString(expectedCallCreate.getData()),
|
resultCallCreate.getData());
|
||||||
Hex.toHexString(resultCallCreate.getData()));
|
if (!assertData) {
|
||||||
logger.info(output);
|
|
||||||
results.add(output);
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean assertGasLimit = Arrays.equals(
|
String output =
|
||||||
expectedCallCreate.getGasLimit(),
|
String.format("Call/Create data is different. Expected: [ %s ], result: [ %s ]",
|
||||||
resultCallCreate.getGasLimit());
|
Hex.toHexString(expectedCallCreate.getData()),
|
||||||
if (!assertGasLimit) {
|
Hex.toHexString(resultCallCreate.getData()));
|
||||||
String output =
|
logger.info(output);
|
||||||
String.format("Call/Create gasLimit is different. Expected: [ %s ], result: [ %s ]",
|
results.add(output);
|
||||||
Hex.toHexString(expectedCallCreate.getGasLimit()),
|
}
|
||||||
Hex.toHexString(resultCallCreate.getGasLimit()));
|
|
||||||
logger.info(output);
|
|
||||||
results.add(output);
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean assertValue = Arrays.equals(
|
boolean assertGasLimit = Arrays.equals(
|
||||||
expectedCallCreate.getValue(),
|
expectedCallCreate.getGasLimit(),
|
||||||
resultCallCreate.getValue());
|
resultCallCreate.getGasLimit());
|
||||||
if (!assertValue) {
|
if (!assertGasLimit) {
|
||||||
String output =
|
String output =
|
||||||
String.format("Call/Create value is different. Expected: [ %s ], result: [ %s ]",
|
String.format("Call/Create gasLimit is different. Expected: [ %s ], result: [ %s ]",
|
||||||
Hex.toHexString(expectedCallCreate.getValue()),
|
Hex.toHexString(expectedCallCreate.getGasLimit()),
|
||||||
Hex.toHexString(resultCallCreate.getValue()));
|
Hex.toHexString(resultCallCreate.getGasLimit()));
|
||||||
logger.info(output);
|
logger.info(output);
|
||||||
results.add(output);
|
results.add(output);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// assert out
|
boolean assertValue = Arrays.equals(
|
||||||
byte[] expectedHReturn = testCase.getOut();
|
expectedCallCreate.getValue(),
|
||||||
byte[] actualHReturn = ByteUtil.EMPTY_BYTE_ARRAY;
|
resultCallCreate.getValue());
|
||||||
if (program.getResult().getHReturn() != null) {
|
if (!assertValue) {
|
||||||
actualHReturn = program.getResult().getHReturn().array();
|
String output =
|
||||||
}
|
String.format("Call/Create value is different. Expected: [ %s ], result: [ %s ]",
|
||||||
|
Hex.toHexString(expectedCallCreate.getValue()),
|
||||||
|
Hex.toHexString(resultCallCreate.getValue()));
|
||||||
|
logger.info(output);
|
||||||
|
results.add(output);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!Arrays.equals(expectedHReturn, actualHReturn)) {
|
// assert out
|
||||||
|
byte[] expectedHReturn = testCase.getOut();
|
||||||
|
byte[] actualHReturn = ByteUtil.EMPTY_BYTE_ARRAY;
|
||||||
|
if (program.getResult().getHReturn() != null) {
|
||||||
|
actualHReturn = program.getResult().getHReturn().array();
|
||||||
|
}
|
||||||
|
|
||||||
String output =
|
if (!Arrays.equals(expectedHReturn, actualHReturn)) {
|
||||||
String.format("HReturn is different. Expected hReturn: [ %s ], actual hReturn: [ %s ]",
|
|
||||||
Hex.toHexString(expectedHReturn),
|
|
||||||
Hex.toHexString(actualHReturn));
|
|
||||||
logger.info(output);
|
|
||||||
results.add(output);
|
|
||||||
}
|
|
||||||
|
|
||||||
// assert gas
|
String output =
|
||||||
BigInteger expectedGas = new BigInteger(testCase.getGas());
|
String.format("HReturn is different. Expected hReturn: [ %s ], actual hReturn: [ %s ]",
|
||||||
BigInteger actualGas = new BigInteger(gas).subtract(BigInteger.valueOf(program.getResult().getGasUsed()));
|
Hex.toHexString(expectedHReturn),
|
||||||
|
Hex.toHexString(actualHReturn));
|
||||||
|
logger.info(output);
|
||||||
|
results.add(output);
|
||||||
|
}
|
||||||
|
|
||||||
if (!expectedGas.equals(actualGas)) {
|
// assert gas
|
||||||
|
BigInteger expectedGas = new BigInteger(testCase.getGas());
|
||||||
|
BigInteger actualGas = new BigInteger(gas).subtract(BigInteger.valueOf(program.getResult().getGasUsed()));
|
||||||
|
|
||||||
|
if (!expectedGas.equals(actualGas)) {
|
||||||
|
|
||||||
|
String output =
|
||||||
|
String.format("Gas remaining is different. Expected gas remaining: [ %s ], actual gas remaining: [ %s ]",
|
||||||
|
expectedGas.toString() ,
|
||||||
|
actualGas.toString());
|
||||||
|
logger.info(output);
|
||||||
|
results.add(output);
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* end of if(testCase.getPost().size() == 0)
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
String output =
|
|
||||||
String.format("Gas remaining is different. Expected gas remaining: [ %s ], actual gas remaining: [ %s ]",
|
|
||||||
expectedGas.toString() ,
|
|
||||||
actualGas.toString());
|
|
||||||
logger.info(output);
|
|
||||||
results.add(output);
|
|
||||||
}
|
|
||||||
return results;
|
return results;
|
||||||
} finally {
|
} finally {
|
||||||
repository.close();
|
repository.close();
|
||||||
|
|
|
@ -21,6 +21,7 @@ public class TestSuite {
|
||||||
for (Object key: testCaseJSONObj.keySet()){
|
for (Object key: testCaseJSONObj.keySet()){
|
||||||
|
|
||||||
Object testCaseJSON = testCaseJSONObj.get(key);
|
Object testCaseJSON = testCaseJSONObj.get(key);
|
||||||
|
|
||||||
TestCase testCase = new TestCase(key.toString(), (JSONObject) testCaseJSON);
|
TestCase testCase = new TestCase(key.toString(), (JSONObject) testCaseJSON);
|
||||||
|
|
||||||
testList.add(testCase);
|
testList.add(testCase);
|
||||||
|
|
|
@ -78,6 +78,8 @@ public class DataWord implements Comparable<DataWord> {
|
||||||
*/
|
*/
|
||||||
public int intValue() {
|
public int intValue() {
|
||||||
BigDecimal tmpValue = new BigDecimal(this.value());
|
BigDecimal tmpValue = new BigDecimal(this.value());
|
||||||
|
if(this.bytesOccupied() > 4)
|
||||||
|
return Integer.MAX_VALUE;
|
||||||
return tmpValue.intValueExact();
|
return tmpValue.intValueExact();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -47,6 +47,7 @@ public class Program {
|
||||||
byte[] ops;
|
byte[] ops;
|
||||||
int pc = 0;
|
int pc = 0;
|
||||||
byte lastOp = 0;
|
byte lastOp = 0;
|
||||||
|
byte previouslyExecutedOp = 0;
|
||||||
boolean stopped = false;
|
boolean stopped = false;
|
||||||
|
|
||||||
ProgramInvoke invokeData;
|
ProgramInvoke invokeData;
|
||||||
|
@ -76,10 +77,30 @@ public class Program {
|
||||||
return ops[pc];
|
return ops[pc];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Last Op can only be set publicly (no getLastOp method), is used for logging
|
||||||
|
* @param op
|
||||||
|
*/
|
||||||
public void setLastOp(byte op) {
|
public void setLastOp(byte op) {
|
||||||
this.lastOp = op;
|
this.lastOp = op;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Should be set only after the OP is fully executed
|
||||||
|
* @param op
|
||||||
|
*/
|
||||||
|
public void setPreviouslyExecutedOp(byte op) {
|
||||||
|
this.previouslyExecutedOp = op;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* returns the last fully executed OP
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public byte getPreviouslyExecutedOp() {
|
||||||
|
return this.previouslyExecutedOp;
|
||||||
|
}
|
||||||
|
|
||||||
public void stackPush(byte[] data) {
|
public void stackPush(byte[] data) {
|
||||||
DataWord stackWord = new DataWord(data);
|
DataWord stackWord = new DataWord(data);
|
||||||
stack.push(stackWord);
|
stack.push(stackWord);
|
||||||
|
|
|
@ -821,8 +821,10 @@ public class VM {
|
||||||
case JUMP:{
|
case JUMP:{
|
||||||
DataWord pos = program.stackPop();
|
DataWord pos = program.stackPop();
|
||||||
int nextPC = pos.intValue(); // possible overflow
|
int nextPC = pos.intValue(); // possible overflow
|
||||||
if (nextPC != 0 && program.getOp(nextPC) != OpCode.JUMPDEST.val())
|
if(program.getPreviouslyExecutedOp() < OpCode.PUSH1.val() || program.getPreviouslyExecutedOp() > OpCode.PUSH32.val()) {
|
||||||
throw program.new BadJumpDestinationException();
|
if (nextPC != 0 && program.getOp(nextPC) != OpCode.JUMPDEST.val())
|
||||||
|
throw program.new BadJumpDestinationException();
|
||||||
|
}
|
||||||
|
|
||||||
if (logger.isInfoEnabled())
|
if (logger.isInfoEnabled())
|
||||||
hint = "~> " + nextPC;
|
hint = "~> " + nextPC;
|
||||||
|
@ -836,8 +838,10 @@ public class VM {
|
||||||
|
|
||||||
if (!cond.isZero()) {
|
if (!cond.isZero()) {
|
||||||
int nextPC = pos.intValue(); // possible overflow
|
int nextPC = pos.intValue(); // possible overflow
|
||||||
if (nextPC != 0 && program.getOp(nextPC) != OpCode.JUMPDEST.val())
|
if(program.getPreviouslyExecutedOp() < OpCode.PUSH1.val() || program.getPreviouslyExecutedOp() > OpCode.PUSH32.val()) {
|
||||||
throw program.new BadJumpDestinationException();
|
if (nextPC != 0 && program.getOp(nextPC) != OpCode.JUMPDEST.val())
|
||||||
|
throw program.new BadJumpDestinationException();
|
||||||
|
}
|
||||||
|
|
||||||
// todo: in case destination is not JUMPDEST, check if prev was strict push
|
// todo: in case destination is not JUMPDEST, check if prev was strict push
|
||||||
// todo: in EP: (ii) If a jump is preceded by a push, no jumpdest required;
|
// todo: in EP: (ii) If a jump is preceded by a push, no jumpdest required;
|
||||||
|
@ -971,6 +975,8 @@ public class VM {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
program.setPreviouslyExecutedOp(op.val());
|
||||||
|
|
||||||
if (logger.isInfoEnabled() && !op.equals(CALL)
|
if (logger.isInfoEnabled() && !op.equals(CALL)
|
||||||
&& !op.equals(CREATE))
|
&& !op.equals(CREATE))
|
||||||
logger.info(logString, stepBefore, String.format("%-12s",
|
logger.info(logString, stepBefore, String.format("%-12s",
|
||||||
|
|
|
@ -11,6 +11,7 @@ import org.junit.runners.MethodSorters;
|
||||||
public class GitHubVMTest {
|
public class GitHubVMTest {
|
||||||
|
|
||||||
@Test // testing full suite
|
@Test // testing full suite
|
||||||
|
@Ignore
|
||||||
public void testArithmeticFromGitHub() throws ParseException {
|
public void testArithmeticFromGitHub() throws ParseException {
|
||||||
|
|
||||||
String json = JSONReader.loadJSON("VMTests/vmArithmeticTest.json");
|
String json = JSONReader.loadJSON("VMTests/vmArithmeticTest.json");
|
||||||
|
@ -18,6 +19,7 @@ public class GitHubVMTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test // testing full suite
|
@Test // testing full suite
|
||||||
|
@Ignore
|
||||||
public void testBitwiseLogicOperationFromGitHub() throws ParseException {
|
public void testBitwiseLogicOperationFromGitHub() throws ParseException {
|
||||||
|
|
||||||
String json = JSONReader.loadJSON("VMTests/vmBitwiseLogicOperationTest.json");
|
String json = JSONReader.loadJSON("VMTests/vmBitwiseLogicOperationTest.json");
|
||||||
|
@ -41,7 +43,6 @@ public class GitHubVMTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test // testing full suite
|
@Test // testing full suite
|
||||||
@Ignore
|
|
||||||
public void testIOandFlowOperationsFromGitHub() throws ParseException {
|
public void testIOandFlowOperationsFromGitHub() throws ParseException {
|
||||||
|
|
||||||
String json = JSONReader.loadJSON("vmtests/vmIOandFlowOperationsTest.json");
|
String json = JSONReader.loadJSON("vmtests/vmIOandFlowOperationsTest.json");
|
||||||
|
|
Loading…
Reference in New Issue