Readded jsontestingsuite.

Removed hibernate dependency.
This commit is contained in:
Adrian Tiberius 2015-05-06 15:59:02 +02:00
parent 2905d43200
commit b85abefebd
18 changed files with 1938 additions and 2 deletions

View File

@ -55,9 +55,11 @@ dependencies {
compile('com.j256.ormlite:ormlite-android:4.48') {
exclude group: 'commons-logging', module: 'commons-logging'
}
/*
compile('com.j256.ormlite:ormlite-jdbc:4.48') {
exclude group: 'commons-logging', module: 'commons-logging'
}
*/
//compile(name:'android-leveldb', ext:'aar')
//compile 'com.snappydb:snappydb-lib:0.5.0'
//compile files('./libs/android.jar')
@ -113,6 +115,7 @@ dependencies {
// best performance - do not upgrade!
compile 'javax.el:javax.el-api:2.2.4'
compile 'org.glassfish.web:javax.el:2.2.4'
/*
compile("org.hibernate:hibernate-core:${hibernateVersion}") {
exclude group: 'dom4j', module: 'dom4j'
exclude group: 'org.jboss.spec.javax.transaction', module: 'jboss-transaction-api_1.2_spec'
@ -121,6 +124,8 @@ dependencies {
exclude group: 'dom4j', module: 'dom4j'
exclude group: 'org.jboss.spec.javax.transaction', module: 'jboss-transaction-api_1.2_spec'
}
*/
compile 'javax.persistence:persistence-api:1.0.2'
//compile ('commons-dbcp:commons-dbcp:1.4') {
// exclude group: 'commons-logging', module: 'commons-logging'

View File

@ -2,7 +2,7 @@ package org.ethereum.facade;
import org.ethereum.db.BlockStore;
import org.ethereum.db.InMemoryBlockStore;
import org.hibernate.SessionFactory;
//import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
//import org.springframework.context.annotation.Bean;
//import org.springframework.context.annotation.Configuration;
@ -23,7 +23,9 @@ public class DefaultConfig {
//@Bean
//@Transactional(propagation = Propagation.SUPPORTS)
/*
public BlockStore blockStore(SessionFactory sessionFactory){
return new InMemoryBlockStore();
}
*/
}

View File

@ -2,7 +2,7 @@ package org.ethereum.facade;
import org.ethereum.db.BlockStore;
import org.ethereum.db.InMemoryBlockStore;
import org.hibernate.SessionFactory;
//import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
//import org.springframework.context.annotation.Bean;
//import org.springframework.context.annotation.Configuration;
@ -26,7 +26,9 @@ public class RemoteConfig {
//@Bean
//@Transactional(propagation = Propagation.SUPPORTS)
/*
public BlockStore blockStore(SessionFactory sessionFactory){
return new InMemoryBlockStore();
}
*/
}

View File

@ -0,0 +1,177 @@
package org.ethereum.jsontestsuite;
import org.ethereum.db.ContractDetails;
import org.ethereum.util.ByteUtil;
import org.ethereum.vm.DataWord;
import org.json.simple.JSONObject;
import org.spongycastle.util.encoders.Hex;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* @author Roman Mandeleil
* @since 28.06.2014
*/
public class AccountState {
byte[] address;
byte[] balance;
byte[] code;
byte[] nonce;
Map<DataWord, DataWord> storage = new HashMap<>();
public AccountState(byte[] address, JSONObject accountState) {
this.address = address;
String balance = accountState.get("balance").toString();
String code = (String) accountState.get("code");
String nonce = accountState.get("nonce").toString();
JSONObject store = (JSONObject) accountState.get("storage");
this.balance = new BigInteger(balance).toByteArray();
if (code != null && code.length() > 2)
this.code = Hex.decode(code.substring(2));
else
this.code = ByteUtil.EMPTY_BYTE_ARRAY;
this.nonce = new BigInteger(nonce).toByteArray();
int size = store.keySet().size();
Object[] keys = store.keySet().toArray();
for (int i = 0; i < size; ++i) {
String keyS = keys[i].toString();
String valS = store.get(keys[i]).toString();
byte[] key = Utils.parseData(keyS);
byte[] value = Utils.parseData(valS);
storage.put(new DataWord(key), new DataWord(value));
}
}
public byte[] getAddress() {
return address;
}
public byte[] getBalance() {
return balance;
}
public BigInteger getBigIntegerBalance() {
return new BigInteger(balance);
}
public byte[] getCode() {
return code;
}
public byte[] getNonce() {
return nonce;
}
public long getNonceLong() {
return new BigInteger(nonce).longValue();
}
public Map<DataWord, DataWord> getStorage() {
return storage;
}
public List<String> compareToReal(org.ethereum.core.AccountState state, ContractDetails details) {
List<String> results = new ArrayList<>();
BigInteger expectedBalance = new BigInteger(1, this.getBalance());
if (!state.getBalance().equals(expectedBalance)) {
String formattedString = String.format("Account: %s: has unexpected balance, expected balance: %s found balance: %s",
Hex.toHexString(this.address), expectedBalance.toString(), state.getBalance().toString());
results.add(formattedString);
}
BigInteger expectedNonce = new BigInteger(1, this.getNonce());
if (!state.getNonce().equals(expectedNonce)) {
state.getNonce();
this.getNonce();
String formattedString = String.format("Account: %s: has unexpected nonce, expected nonce: %s found nonce: %s",
Hex.toHexString(this.address), expectedNonce.toString(), state.getNonce().toString());
results.add(formattedString);
}
if (!Arrays.equals(details.getCode(), this.getCode())) {
String formattedString = String.format("Account: %s: has unexpected nonce, expected nonce: %s found nonce: %s",
Hex.toHexString(this.address), Hex.toHexString(this.getCode()), Hex.toHexString(details.getCode()));
results.add(formattedString);
}
// compare storage
Set<DataWord> keys = details.getStorage().keySet();
Set<DataWord> expectedKeys = this.getStorage().keySet();
Set<DataWord> checked = new HashSet<>();
for (DataWord key : keys) {
DataWord value = details.getStorage().get(key);
DataWord expectedValue = this.getStorage().get(key);
if (expectedValue == null) {
String formattedString = String.format("Account: %s: has unexpected storage data: %s = %s",
Hex.toHexString(this.address),
key.toString(),
value.toString());
results.add(formattedString);
continue;
}
if (!expectedValue.equals(value)) {
String formattedString = String.format("Account: %s: has unexpected value, for key: %s , expectedValue: %s real value: %s",
Hex.toHexString(this.address), key.toString(),
expectedValue.toString(), value.toString());
results.add(formattedString);
continue;
}
checked.add(key);
}
for (DataWord key : expectedKeys) {
if (!checked.contains(key)) {
String formattedString = String.format("Account: %s: doesn't exist expected storage key: %s",
Hex.toHexString(this.address), key.toString());
results.add(formattedString);
}
}
return results;
}
@Override
public String toString() {
return "AccountState{" +
"address=" + Hex.toHexString(address) +
", balance=" + Hex.toHexString(balance) +
", code=" + Hex.toHexString(code) +
", nonce=" + Hex.toHexString(nonce) +
", storage=" + storage +
'}';
}
}

View File

@ -0,0 +1,72 @@
package org.ethereum.jsontestsuite;
import org.ethereum.util.ByteUtil;
import org.json.simple.JSONObject;
import org.spongycastle.util.encoders.Hex;
import java.math.BigInteger;
/**
* @author Roman Mandeleil
* @since 28.06.2014
*/
public class CallCreate {
private final byte[] data;
private final byte[] destination;
private final byte[] gasLimit;
private final byte[] value;
/* e.g.
"data" : [
],
"destination" : "cd1722f3947def4cf144679da39c4c32bdc35681",
"gasLimit" : 9792,
"value" : 74
*/
public CallCreate(JSONObject callCreateJSON) {
String data = callCreateJSON.get("data").toString();
String destination = callCreateJSON.get("destination").toString();
String gasLimit = callCreateJSON.get("gasLimit").toString();
String value = callCreateJSON.get("value").toString();
if (data != null && data.length() > 2)
this.data = Hex.decode(data.substring(2));
else
this.data = ByteUtil.EMPTY_BYTE_ARRAY;
this.destination = Hex.decode(destination);
this.gasLimit = ByteUtil.bigIntegerToBytes(new BigInteger(gasLimit));
this.value = ByteUtil.bigIntegerToBytes(new BigInteger(value));
}
public byte[] getData() {
return data;
}
public byte[] getDestination() {
return destination;
}
public byte[] getGasLimit() {
return gasLimit;
}
public byte[] getValue() {
return value;
}
@Override
public String toString() {
return "CallCreate{" +
"data=" + Hex.toHexString(data) +
", destination=" + Hex.toHexString(destination) +
", gasLimit=" + Hex.toHexString(gasLimit) +
", value=" + Hex.toHexString(value) +
'}';
}
}

View File

@ -0,0 +1,86 @@
package org.ethereum.jsontestsuite;
import org.json.simple.JSONObject;
import org.spongycastle.util.BigIntegers;
import org.spongycastle.util.encoders.Hex;
import java.math.BigInteger;
/**
* @author Roman Mandeleil
* @since 28.06.2014
*/
public class Env {
private final byte[] currentCoinbase;
private final byte[] currentDifficulty;
private final byte[] currentGasLimit;
private final byte[] currentNumber;
private final byte[] currentTimestamp;
private final byte[] previousHash;
/*
e.g:
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba",
"currentDifficulty" : "256",
"currentGasLimit" : "1000000",
"currentNumber" : "0",
"currentTimestamp" : 1,
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
*/
public Env(JSONObject env) {
String coinbase = env.get("currentCoinbase").toString();
String difficulty = env.get("currentDifficulty").toString();
String timestamp = env.get("currentTimestamp").toString();
String number = env.get("currentNumber").toString();
String gasLimit = env.get("currentGasLimit").toString();
String prevHash = env.get("previousHash").toString();
this.currentCoinbase = Hex.decode(coinbase);
this.currentDifficulty = BigIntegers.asUnsignedByteArray( new BigInteger(difficulty) );
this.currentGasLimit = BigIntegers.asUnsignedByteArray(new BigInteger(gasLimit));
this.currentNumber = new BigInteger(number).toByteArray();
this.currentTimestamp = new BigInteger(timestamp).toByteArray();
this.previousHash = Hex.decode(prevHash);
}
public byte[] getCurrentCoinbase() {
return currentCoinbase;
}
public byte[] getCurrentDifficulty() {
return currentDifficulty;
}
public byte[] getCurrentGasLimit() {
return currentGasLimit;
}
public byte[] getCurrentNumber() {
return currentNumber;
}
public byte[] getCurrentTimestamp() {
return currentTimestamp;
}
public byte[] getPreviousHash() {
return previousHash;
}
@Override
public String toString() {
return "Env{" +
"currentCoinbase=" + Hex.toHexString(currentCoinbase) +
", currentDifficulty=" + Hex.toHexString(currentDifficulty) +
", currentGasLimit=" + Hex.toHexString(currentGasLimit) +
", currentNumber=" + Hex.toHexString(currentNumber) +
", currentTimestamp=" + Hex.toHexString(currentTimestamp) +
", previousHash=" + Hex.toHexString(previousHash) +
'}';
}
}

View File

@ -0,0 +1,123 @@
package org.ethereum.jsontestsuite;
import org.ethereum.util.ByteUtil;
import org.json.simple.JSONObject;
import org.spongycastle.util.encoders.Hex;
import java.math.BigInteger;
/**
* @author Roman Mandeleil
* @since 28.06.2014
*/
public class Exec {
private final byte[] address;
private final byte[] caller;
private final byte[] data;
private final byte[] code;
private final byte[] gas;
private final byte[] gasPrice;
private final byte[] origin;
private final byte[] value;
/*
e.g:
"address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6",
"caller" : "cd1722f3947def4cf144679da39c4c32bdc35681",
"data" : [
],
"code" : [ 96,0,96,0,96,0,96,0,96,74,51,96,200,92,3,241 ],
"gas" : 10000,
"gasPrice" : 100000000000000,
"origin" : "cd1722f3947def4cf144679da39c4c32bdc35681",
"value" : 1000000000000000000
*/
public Exec(JSONObject exec) {
String address = exec.get("address").toString();
String caller = exec.get("caller").toString();
String code = exec.get("code").toString();
String data = exec.get("data").toString();
String gas = exec.get("gas").toString();
String gasPrice = exec.get("gasPrice").toString();
String origin = exec.get("origin").toString();
String value = exec.get("value").toString();
this.address = Hex.decode(address);
this.caller = Hex.decode(caller);
if (code != null && code.length() > 2)
this.code = Hex.decode(code.substring(2));
else
this.code = ByteUtil.EMPTY_BYTE_ARRAY;
if (data != null && data.length() > 2)
this.data = Hex.decode(data.substring(2));
else
this.data = ByteUtil.EMPTY_BYTE_ARRAY;
this.gas = ByteUtil.bigIntegerToBytes(new BigInteger(gas));
this.gasPrice = ByteUtil.bigIntegerToBytes(new BigInteger(gasPrice));
this.origin = Hex.decode(origin);
this.value = ByteUtil.bigIntegerToBytes(new BigInteger(value));
}
public byte[] getAddress() {
return address;
}
public byte[] getCaller() {
return caller;
}
public byte[] getData() {
return data;
}
public byte[] getCode() {
return code;
}
public byte[] getGas() {
return gas;
}
public byte[] getGasPrice() {
return gasPrice;
}
public byte[] getOrigin() {
return origin;
}
public byte[] getValue() {
return value;
}
@Override
public String toString() {
return "Exec{" +
"address=" + Hex.toHexString(address) +
", caller=" + Hex.toHexString(caller) +
", data=" + Hex.toHexString(data) +
", code=" + Hex.toHexString(data) +
", gas=" + Hex.toHexString(gas) +
", gasPrice=" + Hex.toHexString(gasPrice) +
", origin=" + Hex.toHexString(origin) +
", value=" + Hex.toHexString(value) +
'}';
}
}

View File

@ -0,0 +1,79 @@
package org.ethereum.jsontestsuite;
import org.ethereum.util.ByteUtil;
import org.json.simple.JSONArray;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.spongycastle.util.encoders.Hex;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.math.BigInteger;
import java.util.regex.Pattern;
/**
* @author Roman Mandeleil
* @since 28.06.2014
*/
public class Helper {
private static Logger logger = LoggerFactory.getLogger("misc");
public static byte[] parseDataArray(JSONArray valArray) {
// value can be:
// 1. 324234 number
// 2. "0xAB3F23A" - hex string
// 3. "239472398472" - big number
ByteArrayOutputStream bos = new ByteArrayOutputStream();
for (Object val : valArray) {
if (val instanceof String) {
// Hex num
boolean hexVal = Pattern.matches("0[xX][0-9a-fA-F]+", val.toString());
if (hexVal) {
String number = ((String) val).substring(2);
if (number.length() % 2 == 1) number = "0" + number;
byte[] data = Hex.decode(number);
try {
bos.write(data);
} catch (IOException e) {
logger.error("should not happen", e);
}
} else {
// BigInt num
boolean isNumeric = Pattern.matches("[0-9a-fA-F]+", val.toString());
if (!isNumeric) throw new Error("Wrong test case JSON format");
else {
BigInteger value = new BigInteger(val.toString());
try {
bos.write(value.toByteArray());
} catch (IOException e) {
logger.error("should not happen", e);
}
}
}
} else if (val instanceof Long) {
// Simple long
byte[] data = ByteUtil.bigIntegerToBytes(BigInteger.valueOf((Long) val));
try {
bos.write(data);
} catch (IOException e) {
logger.error("should not happen", e);
}
} else {
throw new Error("Wrong test case JSON format");
}
}
return bos.toByteArray();
}
}

View File

@ -0,0 +1,134 @@
package org.ethereum.jsontestsuite;
import org.ethereum.config.SystemProperties;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.apache.commons.codec.binary.Base64;
public class JSONReader {
public static String loadJSON(String filename) {
String json = "";
if (!SystemProperties.CONFIG.vmTestLoadLocal())
json = getFromUrl("https://raw.githubusercontent.com/ethereum/tests/develop/" + filename);
return json.isEmpty() ? getFromLocal(filename) : json;
}
public static String loadJSONFromCommit(String filename, String shacommit) {
String json = "";
if (!SystemProperties.CONFIG.vmTestLoadLocal())
json = getFromUrl("https://raw.githubusercontent.com/ethereum/tests/" + shacommit + "/" + filename);
return json.isEmpty() ? getFromLocal(filename) : json;
}
public static String getFromLocal(String filename) {
System.out.println("Loading local file: " + filename);
try {
if (System.getProperty("ETHEREUM_TEST_PATH") == null) {
System.out.println("ETHEREUM_TEST_PATH is not passed as a VM argument, please make sure you pass it " +
"with the correct path");
return "";
}
System.out.println("From: " + System.getProperty("ETHEREUM_TEST_PATH"));
File vmTestFile = new File(System.getProperty("ETHEREUM_TEST_PATH") + filename);
return new String(Files.readAllBytes(vmTestFile.toPath()));
} catch (IOException e) {
e.printStackTrace();
}
return "";
}
public static String getFromUrl(String urlToRead) {
URL url;
HttpURLConnection conn;
BufferedReader rd;
String line;
String result = "";
try {
url = new URL(urlToRead);
conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
conn.setDoOutput(true);
conn.connect();
InputStream in = conn.getInputStream();
rd = new BufferedReader(new InputStreamReader(in));
System.out.println("Loading remote file: " + urlToRead);
while ((line = rd.readLine()) != null) {
result += line;
}
rd.close();
} catch (Throwable e) {
e.printStackTrace();
}
return result;
}
public static String getTestBlobForTreeSha(String shacommit, String testcase){
String result = getFromUrl("https://api.github.com/repos/ethereum/tests/git/trees/" + shacommit);
JSONParser parser = new JSONParser();
JSONObject testSuiteObj = null;
List<String> fileNames = new ArrayList<String>();
try {
testSuiteObj = (JSONObject) parser.parse(result);
JSONArray tree = (JSONArray)testSuiteObj.get("tree");
for (Object oEntry : tree) {
JSONObject entry = (JSONObject) oEntry;
String testName = (String) entry.get("path");
if ( testName.equals(testcase) ) {
String blobresult = getFromUrl( (String) entry.get("url") );
testSuiteObj = (JSONObject) parser.parse(blobresult);
String blob = (String) testSuiteObj.get("content");
byte[] valueDecoded= Base64.decodeBase64(blob.getBytes() );
//System.out.println("Decoded value is " + new String(valueDecoded));
return new String(valueDecoded);
}
}
} catch (ParseException e) {e.printStackTrace();}
return "";
}
public static List<String> getFileNamesForTreeSha(String sha){
String result = getFromUrl("https://api.github.com/repos/ethereum/tests/git/trees/" + sha);
JSONParser parser = new JSONParser();
JSONObject testSuiteObj = null;
List<String> fileNames = new ArrayList<String>();
try {
testSuiteObj = (JSONObject) parser.parse(result);
JSONArray tree = (JSONArray)testSuiteObj.get("tree");
for (Object oEntry : tree) {
JSONObject entry = (JSONObject) oEntry;
String testName = (String) entry.get("path");
fileNames.add(testName);
}
} catch (ParseException e) {e.printStackTrace();}
return fileNames;
}
}

View File

@ -0,0 +1,107 @@
package org.ethereum.jsontestsuite;
import org.ethereum.vm.DataWord;
import org.ethereum.vm.LogInfo;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.spongycastle.util.encoders.Hex;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class Logs {
List<LogInfo> logs = new ArrayList<>();
public Logs(JSONArray jLogs) {
for (Object jLog1 : jLogs) {
JSONObject jLog = (JSONObject) jLog1;
byte[] address = Hex.decode((String) jLog.get("address"));
byte[] data = Hex.decode(((String) jLog.get("data")).substring(2));
List<DataWord> topics = new ArrayList<>();
JSONArray jTopics = (JSONArray) jLog.get("topics");
for (Object t : jTopics.toArray()) {
byte[] topic = Hex.decode(((String) t));
topics.add(new DataWord(topic));
}
LogInfo li = new LogInfo(address, topics, data);
logs.add(li);
}
}
public Iterator<LogInfo> getIterator() {
return logs.iterator();
}
public List<String> compareToReal(List<LogInfo> logs) {
List<String> results = new ArrayList<>();
int i = 0;
for (LogInfo postLog : this.logs) {
LogInfo realLog = logs.get(i);
String postAddress = Hex.toHexString(postLog.getAddress());
String realAddress = Hex.toHexString(realLog.getAddress());
if (!postAddress.equals(realAddress)) {
String formattedString = String.format("Log: %s: has unexpected address, expected address: %s found address: %s",
i, postAddress, realAddress);
results.add(formattedString);
}
String postData = Hex.toHexString(postLog.getData());
String realData = Hex.toHexString(realLog.getData());
if (!postData.equals(realData)) {
String formattedString = String.format("Log: %s: has unexpected data, expected data: %s found data: %s",
i, postData, realData);
results.add(formattedString);
}
String postBloom = Hex.toHexString(postLog.getBloom().getData());
String realBloom = Hex.toHexString(realLog.getBloom().getData());
if (!postData.equals(realData)) {
String formattedString = String.format("Log: %s: has unexpected bloom, expected bloom: %s found bloom: %s",
i, postBloom, realBloom);
results.add(formattedString);
}
List<DataWord> postTopics = postLog.getTopics();
List<DataWord> realTopics = realLog.getTopics();
int j = 0;
for (DataWord postTopic : postTopics) {
DataWord realTopic = realTopics.get(j);
if (!postTopic.equals(realTopic)) {
String formattedString = String.format("Log: %s: has unexpected topic: %s, expected topic: %s found topic: %s",
i, j, postTopic, realTopic);
results.add(formattedString);
}
++j;
}
++i;
}
return results;
}
}

View File

@ -0,0 +1,123 @@
package org.ethereum.jsontestsuite;
import org.ethereum.db.ByteArrayWrapper;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.json.simple.parser.ParseException;
import org.spongycastle.util.encoders.Hex;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
/**
* @author Roman Mandeleil
* @since 15.12.2014
*/
public class StateTestCase {
private String name = "";
private Env env;
private Logs logs;
private byte[] out;
// "pre": { ... },
private Map<ByteArrayWrapper, AccountState> pre = new HashMap<>();
// "post": { ... },
private Map<ByteArrayWrapper, AccountState> post = new HashMap<>();
private Transaction transaction;
public StateTestCase(String name, JSONObject testCaseJSONObj) throws ParseException {
this(testCaseJSONObj);
this.name = name;
}
public StateTestCase(JSONObject testCaseJSONObj) throws ParseException {
try {
JSONObject envJSON = (JSONObject) testCaseJSONObj.get("env");
JSONArray logsJSON = (JSONArray) testCaseJSONObj.get("logs");
String outStr = testCaseJSONObj.get("out").toString();
JSONObject txJSON = (JSONObject) testCaseJSONObj.get("transaction");
JSONObject preJSON = (JSONObject) testCaseJSONObj.get("pre");
JSONObject postJSON = (JSONObject) testCaseJSONObj.get("post");
this.env = new Env(envJSON);
this.logs = new Logs(logsJSON);
this.out = Utils.parseData(outStr);
this.transaction = new Transaction(txJSON);
for (Object key : preJSON.keySet()) {
byte[] keyBytes = Hex.decode(key.toString());
AccountState accountState =
new AccountState(keyBytes, (JSONObject) preJSON.get(key));
pre.put(new ByteArrayWrapper(keyBytes), accountState);
}
for (Object key : postJSON.keySet()) {
byte[] keyBytes = Hex.decode(key.toString());
AccountState accountState =
new AccountState(keyBytes, (JSONObject) postJSON.get(key));
post.put(new ByteArrayWrapper(keyBytes), accountState);
}
} catch (Throwable e) {
throw new ParseException(0, e);
}
}
public String getName() {
return name;
}
public Env getEnv() {
return env;
}
public Logs getLogs() {
return logs;
}
public byte[] getOut() {
return out;
}
public Map<ByteArrayWrapper, AccountState> getPre() {
return pre;
}
public Map<ByteArrayWrapper, AccountState> getPost() {
return post;
}
public Transaction getTransaction() {
return transaction;
}
@Override
public String toString() {
return "StateTestCase{" +
"name='" + name + '\'' +
", env=" + env +
", logs=" + logs +
", out=" + Arrays.toString(out) +
", pre=" + pre +
", post=" + post +
", transaction=" + transaction +
'}';
}
}

View File

@ -0,0 +1,47 @@
package org.ethereum.jsontestsuite;
import org.json.simple.JSONObject;
import org.json.simple.parser.ParseException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
/**
* @author Roman Mandeleil
* @since 10.07.2014
*/
public class StateTestSuite {
private Logger logger = LoggerFactory.getLogger("TCK-Test");
Map<String, StateTestCase> testCases = new HashMap<>();
public StateTestSuite(JSONObject testCaseJSONObj) throws ParseException {
for (Object key : testCaseJSONObj.keySet()) {
Object testCaseJSON = testCaseJSONObj.get(key);
StateTestCase testCase = new StateTestCase(key.toString(), (JSONObject) testCaseJSON);
testCases.put(key.toString(), testCase);
}
}
public StateTestCase getTestCase(String name) {
StateTestCase testCase = testCases.get(name);
if (testCase == null) throw new NullPointerException("Test cases doesn't exist: " + name);
return testCase;
}
public Collection<StateTestCase> getAllTests() {
return testCases.values();
}
}

View File

@ -0,0 +1,171 @@
package org.ethereum.jsontestsuite;
import org.ethereum.db.ByteArrayWrapper;
import org.ethereum.util.ByteUtil;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.json.simple.parser.ParseException;
import org.spongycastle.util.BigIntegers;
import org.spongycastle.util.encoders.Hex;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @author Roman Mandeleil
* @since 28.06.2014
*/
public class TestCase {
private String name = "";
// "env": { ... },
private Env env;
//
private Logs logs;
// "exec": { ... },
private Exec exec;
// "gas": { ... },
private byte[] gas;
// "out": { ... },
private byte[] out;
// "pre": { ... },
private Map<ByteArrayWrapper, AccountState> pre = new HashMap<>();
// "post": { ... },
private Map<ByteArrayWrapper, AccountState> post = new HashMap<>();
// "callcreates": { ... }
private List<CallCreate> callCreateList = new ArrayList<>();
public TestCase(String name, JSONObject testCaseJSONObj) throws ParseException {
this(testCaseJSONObj);
this.name = name;
}
public TestCase(JSONObject testCaseJSONObj) throws ParseException {
try {
JSONObject envJSON = (JSONObject) testCaseJSONObj.get("env");
JSONObject execJSON = (JSONObject) testCaseJSONObj.get("exec");
JSONObject preJSON = (JSONObject) testCaseJSONObj.get("pre");
JSONObject postJSON = new JSONObject();
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");
JSONArray logsJSON = new JSONArray();
if (testCaseJSONObj.containsKey("logs"))
logsJSON = (JSONArray) testCaseJSONObj.get("logs");
logs = new Logs(logsJSON);
String gasString = "0";
if (testCaseJSONObj.containsKey("gas"))
gasString = testCaseJSONObj.get("gas").toString();
this.gas = BigIntegers.asUnsignedByteArray(new BigInteger(gasString));
String outString = null;
if (testCaseJSONObj.containsKey("out"))
outString = testCaseJSONObj.get("out").toString();
if (outString != null && outString.length() > 2)
this.out = Hex.decode(outString.substring(2));
else
this.out = ByteUtil.EMPTY_BYTE_ARRAY;
for (Object key : preJSON.keySet()) {
byte[] keyBytes = Hex.decode(key.toString());
AccountState accountState =
new AccountState(keyBytes, (JSONObject) preJSON.get(key));
pre.put(new ByteArrayWrapper(keyBytes), accountState);
}
for (Object key : postJSON.keySet()) {
byte[] keyBytes = Hex.decode(key.toString());
AccountState accountState =
new AccountState(keyBytes, (JSONObject) postJSON.get(key));
post.put(new ByteArrayWrapper(keyBytes), accountState);
}
for (Object callCreate : callCreates) {
CallCreate cc = new CallCreate((JSONObject) callCreate);
this.callCreateList.add(cc);
}
this.env = new Env(envJSON);
this.exec = new Exec(execJSON);
} catch (Throwable e) {
throw new ParseException(0, e);
}
}
public Env getEnv() {
return env;
}
public Exec getExec() {
return exec;
}
public Logs getLogs() {
return logs;
}
public byte[] getGas() {
return gas;
}
public byte[] getOut() {
return out;
}
public Map<ByteArrayWrapper, AccountState> getPre() {
return pre;
}
public Map<ByteArrayWrapper, AccountState> getPost() {
return post;
}
public List<CallCreate> getCallCreateList() {
return callCreateList;
}
public String getName() {
return name;
}
@Override
public String toString() {
return "TestCase{" +
"" + env +
", " + exec +
", gas=" + Hex.toHexString(gas) +
", out=" + Hex.toHexString(out) +
", pre=" + pre +
", post=" + post +
", callcreates=" + callCreateList +
'}';
}
}

View File

@ -0,0 +1,96 @@
package org.ethereum.jsontestsuite;
import org.ethereum.core.Block;
import org.ethereum.core.Transaction;
import org.ethereum.db.BlockStore;
import org.ethereum.facade.Repository;
import org.ethereum.util.ByteUtil;
import org.ethereum.vm.DataWord;
import org.ethereum.vm.Program;
import org.ethereum.vm.ProgramInvoke;
import org.ethereum.vm.ProgramInvokeFactory;
import org.ethereum.vm.ProgramInvokeImpl;
import java.math.BigInteger;
/**
* @author Roman Mandeleil
* @since 19.12.2014
*/
public class TestProgramInvokeFactory implements ProgramInvokeFactory {
private final Env env;
TestProgramInvokeFactory(Env env) {
this.env = env;
}
@Override
public ProgramInvoke createProgramInvoke(Transaction tx, Block block, Repository repository, BlockStore blockStore) {
return generalInvoke(tx, repository, blockStore);
}
@Override
public ProgramInvoke createProgramInvoke(Program program, DataWord toAddress, DataWord inValue, DataWord inGas,
BigInteger balanceInt, byte[] dataIn,
Repository repository, BlockStore blockStore, boolean byTestingSuite) {
return null;
}
private ProgramInvoke generalInvoke(Transaction tx, Repository repository, BlockStore blockStore) {
/*** ADDRESS op ***/
// YP: Get address of currently executing account.
byte[] address = tx.isContractCreation() ? tx.getContractAddress() : tx.getReceiveAddress();
/*** ORIGIN op ***/
// YP: This is the sender of original transaction; it is never a contract.
byte[] origin = tx.getSender();
/*** CALLER op ***/
// YP: This is the address of the account that is directly responsible for this execution.
byte[] caller = tx.getSender();
/*** BALANCE op ***/
byte[] balance = repository.getBalance(address).toByteArray();
/*** GASPRICE op ***/
byte[] gasPrice = tx.getGasPrice();
/*** GAS op ***/
byte[] gas = tx.getGasLimit();
/*** CALLVALUE op ***/
byte[] callValue = tx.getValue() == null ? new byte[]{0} : tx.getValue();
/*** CALLDATALOAD op ***/
/*** CALLDATACOPY op ***/
/*** CALLDATASIZE op ***/
byte[] data = tx.getData() == null ? ByteUtil.EMPTY_BYTE_ARRAY : tx.getData();
/*** PREVHASH op ***/
byte[] lastHash = env.getPreviousHash();
/*** COINBASE op ***/
byte[] coinbase = env.getCurrentCoinbase();
/*** TIMESTAMP op ***/
long timestamp = ByteUtil.byteArrayToLong(env.getCurrentTimestamp());
/*** NUMBER op ***/
long number = ByteUtil.byteArrayToLong(env.getCurrentNumber());
/*** DIFFICULTY op ***/
byte[] difficulty = env.getCurrentDifficulty();
/*** GASLIMIT op ***/
long gaslimit = ByteUtil.byteArrayToLong(env.getCurrentGasLimit());
return new ProgramInvokeImpl(address, origin, caller, balance,
gasPrice, gas, callValue, data, lastHash, coinbase,
timestamp, number, difficulty, gaslimit, repository, blockStore);
}
}

View File

@ -0,0 +1,562 @@
package org.ethereum.jsontestsuite;
import org.ethereum.core.BlockchainImpl;
import org.ethereum.core.Block;
import org.ethereum.core.TransactionExecutor;
import org.ethereum.db.*;
import org.ethereum.facade.Repository;
import org.ethereum.util.ByteUtil;
import org.ethereum.vm.DataWord;
import org.ethereum.vm.LogInfo;
import org.ethereum.vm.Program;
import org.ethereum.vm.ProgramInvoke;
import org.ethereum.vm.ProgramInvokeFactory;
import org.ethereum.vm.ProgramInvokeImpl;
import org.ethereum.vm.VM;
import org.ethereum.vmtrace.ProgramTrace;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.spongycastle.util.encoders.Hex;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import static org.ethereum.util.ByteUtil.*;
/**
* @author Roman Mandeleil
* @since 02.07.2014
*/
public class TestRunner {
private Logger logger = LoggerFactory.getLogger("TCK-Test");
private ProgramTrace trace = null;
public List<String> runTestSuite(TestSuite testSuite) {
Iterator<TestCase> testIterator = testSuite.iterator();
List<String> resultCollector = new ArrayList<>();
while (testIterator.hasNext()) {
TestCase testCase = testIterator.next();
TestRunner runner = new TestRunner();
List<String> result = runner.runTestCase(testCase);
resultCollector.addAll(result);
}
return resultCollector;
}
public List<String> runTestCase(StateTestCase testCase) {
List<String> results = new ArrayList<>();
logger.info("\n***");
logger.info(" Running test case: [" + testCase.getName() + "]");
logger.info("***\n");
logger.info("--------- PRE ---------");
RepositoryImpl repository = loadRepository(new RepositoryDummy(), testCase.getPre());
logger.info("loaded repository");
org.ethereum.core.Transaction tx = createTransaction(testCase.getTransaction());
logger.info("transaction: {}", tx.toString());
byte[] secretKey = testCase.getTransaction().secretKey;
logger.info("sign tx with: {}", Hex.toHexString(secretKey));
tx.sign(secretKey);
BlockchainImpl blockchain = new BlockchainImpl();
blockchain.setRepository(repository);
byte[] coinbase = testCase.getEnv().getCurrentCoinbase();
ProgramInvokeFactory invokeFactory = new TestProgramInvokeFactory(testCase.getEnv());
Block block = new Block(
ByteUtil.EMPTY_BYTE_ARRAY,
ByteUtil.EMPTY_BYTE_ARRAY,
coinbase,
ByteUtil.EMPTY_BYTE_ARRAY,
testCase.getEnv().getCurrentDifficulty(),
new BigInteger(1, testCase.getEnv().getCurrentNumber()).longValue(),
new BigInteger(1, testCase.getEnv().getCurrentGasLimit()).longValue(),
0L,
new BigInteger(1, testCase.getEnv().getCurrentTimestamp()).longValue(),
ByteUtil.ZERO_BYTE_ARRAY,
ByteUtil.ZERO_BYTE_ARRAY,
null, null);
blockchain.setBestBlock(block);
blockchain.setProgramInvokeFactory(invokeFactory);
blockchain.startTracking();
Repository track = repository.startTracking();
TransactionExecutor executor =
new TransactionExecutor(tx, coinbase, track, new BlockStoreDummy(),
invokeFactory, blockchain.getBestBlock());
executor.execute();
track.commit();
logger.info("compare results");
List<LogInfo> logs = null;
if (executor.getResult() != null)
logs = executor.getResult().getLogInfoList();
List<String> logResults = testCase.getLogs().compareToReal(logs);
results.addAll(logResults);
Set<ByteArrayWrapper> fullAddressSet = repository.getFullAddressSet();
int repoSize = 0;
for (ByteArrayWrapper addrWrapped : fullAddressSet) {
byte[] addr = addrWrapped.getData();
org.ethereum.core.AccountState accountState = repository.getAccountState(addr);
ContractDetails contractDetails = repository.getContractDetails(addr);
logger.info("{} \n{} \n{}", Hex.toHexString(addr),
accountState.toString(), contractDetails.toString());
logger.info("");
AccountState expectedAccountState = testCase.getPost().get(wrap(addr));
if (expectedAccountState == null) {
String formattedString = String.format("Unexpected account state: address: %s", Hex.toHexString(addr));
results.add(formattedString);
continue;
}
List<String> result = expectedAccountState.compareToReal(accountState, contractDetails);
results.addAll(result);
++repoSize;
}
int postRepoSize = testCase.getPost().size();
if (postRepoSize > repoSize) {
results.add("ERROR: Expected 'Post' repository contains more accounts than executed repository ");
logger.info("Full address set: " + fullAddressSet);
}
return results;
}
public List<String> runTestCase(TestCase testCase) {
logger.info("\n***");
logger.info(" Running test case: [" + testCase.getName() + "]");
logger.info("***\n");
List<String> results = new ArrayList<>();
logger.info("--------- PRE ---------");
RepositoryImpl repository = loadRepository(new RepositoryVMTestDummy(), testCase.getPre());
try {
/* 2. Create ProgramInvoke - Env/Exec */
Env env = testCase.getEnv();
Exec exec = testCase.getExec();
Logs logs = testCase.getLogs();
byte[] address = exec.getAddress();
byte[] origin = exec.getOrigin();
byte[] caller = exec.getCaller();
byte[] balance = ByteUtil.bigIntegerToBytes(repository.getBalance(exec.getAddress()));
byte[] gasPrice = exec.getGasPrice();
byte[] gas = exec.getGas();
byte[] callValue = exec.getValue();
byte[] msgData = exec.getData();
byte[] lastHash = env.getPreviousHash();
byte[] coinbase = env.getCurrentCoinbase();
long timestamp = ByteUtil.byteArrayToLong(env.getCurrentTimestamp());
long number = ByteUtil.byteArrayToLong(env.getCurrentNumber());
byte[] difficulty = env.getCurrentDifficulty();
long gaslimit = new BigInteger(env.getCurrentGasLimit()).longValue();
// Origin and caller need to exist in order to be able to execute
if (repository.getAccountState(origin) == null)
repository.createAccount(origin);
if (repository.getAccountState(caller) == null)
repository.createAccount(caller);
ProgramInvoke programInvoke = new ProgramInvokeImpl(address, origin, caller, balance,
gasPrice, gas, callValue, msgData, lastHash, coinbase,
timestamp, number, difficulty, gaslimit, repository, new BlockStoreDummy(), true);
/* 3. Create Program - exec.code */
/* 4. run VM */
VM vm = new VM();
Program program = new Program(exec.getCode(), programInvoke);
boolean vmDidThrowAnEception = false;
RuntimeException e = null;
try {
while (!program.isStopped())
vm.step(program);
} catch (RuntimeException ex) {
vmDidThrowAnEception = true;
e = ex;
}
program.saveProgramTraceToFile(testCase.getName());
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;
}
this.trace = program.getProgramTrace();
System.out.println("--------- POST --------");
/* 5. Assert Post values */
for (ByteArrayWrapper key : testCase.getPost().keySet()) {
AccountState accountState = testCase.getPost().get(key);
long expectedNonce = accountState.getNonceLong();
BigInteger expectedBalance = accountState.getBigIntegerBalance();
byte[] expectedCode = accountState.getCode();
boolean accountExist = (null != repository.getAccountState(key.getData()));
if (!accountExist) {
String output =
String.format("The expected account does not exist. key: [ %s ]",
Hex.toHexString(key.getData()));
logger.info(output);
results.add(output);
continue;
}
long actualNonce = repository.getNonce(key.getData()).longValue();
BigInteger actualBalance = repository.getBalance(key.getData());
byte[] actualCode = repository.getCode(key.getData());
if (actualCode == null) actualCode = "".getBytes();
if (expectedNonce != actualNonce) {
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);
}
if (!expectedBalance.equals(actualBalance)) {
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);
}
if (!Arrays.equals(expectedCode, actualCode)) {
String output =
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
Map<DataWord, DataWord> storage = accountState.getStorage();
for (DataWord storageKey : storage.keySet()) {
byte[] expectedStValue = storage.get(storageKey).getData();
ContractDetails contractDetails =
program.getResult().getRepository().getContractDetails(accountState.getAddress());
if (contractDetails == null) {
String output =
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();
DataWord actualValue = testStorage.get(new DataWord(storageKey.getData()));
if (actualValue == null ||
!Arrays.equals(expectedStValue, actualValue.getData())) {
String output =
String.format("Storage value different: key [ %s ], expectedValue: [ %s ], actualValue: [ %s ]",
Hex.toHexString(storageKey.getData()),
Hex.toHexString(expectedStValue),
actualValue == null ? "" : Hex.toHexString(actualValue.getNoLeadZeroesData()));
logger.info(output);
results.add(output);
}
}
/* asset logs */
List<LogInfo> logResult = program.getResult().getLogInfoList();
Iterator<LogInfo> postLogs = logs.getIterator();
int i = 0;
while (postLogs.hasNext()) {
LogInfo expectedLogInfo = postLogs.next();
LogInfo foundLogInfo = null;
if (logResult.size() > i)
foundLogInfo = logResult.get(i);
if (foundLogInfo == null) {
String output =
String.format("Expected log [ %s ]", expectedLogInfo.toString());
logger.info(output);
results.add(output);
} else {
if (!Arrays.equals(expectedLogInfo.getAddress(), foundLogInfo.getAddress())) {
String output =
String.format("Expected address [ %s ], found [ %s ]", Hex.toHexString(expectedLogInfo.getAddress()), Hex.toHexString(foundLogInfo.getAddress()));
logger.info(output);
results.add(output);
}
if (!Arrays.equals(expectedLogInfo.getData(), foundLogInfo.getData())) {
String output =
String.format("Expected data [ %s ], found [ %s ]", Hex.toHexString(expectedLogInfo.getData()), Hex.toHexString(foundLogInfo.getData()));
logger.info(output);
results.add(output);
}
if (!expectedLogInfo.getBloom().equals(foundLogInfo.getBloom())) {
String output =
String.format("Expected bloom [ %s ], found [ %s ]",
Hex.toHexString(expectedLogInfo.getBloom().getData()),
Hex.toHexString(foundLogInfo.getBloom().getData()));
logger.info(output);
results.add(output);
}
if (expectedLogInfo.getTopics().size() != foundLogInfo.getTopics().size()) {
String output =
String.format("Expected number of topics [ %d ], found [ %d ]",
expectedLogInfo.getTopics().size(), foundLogInfo.getTopics().size());
logger.info(output);
results.add(output);
} else {
int j = 0;
for (DataWord topic : expectedLogInfo.getTopics()) {
byte[] foundTopic = foundLogInfo.getTopics().get(j).getData();
if (!Arrays.equals(topic.getData(), foundTopic)) {
String output =
String.format("Expected topic [ %s ], found [ %s ]", Hex.toHexString(topic.getData()), Hex.toHexString(foundTopic));
logger.info(output);
results.add(output);
}
++j;
}
}
}
++i;
}
}
// TODO: assert that you have no extra accounts in the repository
// TODO: -> basically the deleted by suicide should be deleted
// TODO: -> and no unexpected created
List<org.ethereum.vm.CallCreate> resultCallCreates =
program.getResult().getCallCreateList();
// assert call creates
for (int i = 0; i < testCase.getCallCreateList().size(); ++i) {
org.ethereum.vm.CallCreate resultCallCreate = null;
if (resultCallCreates != null && resultCallCreates.size() > i) {
resultCallCreate = resultCallCreates.get(i);
}
CallCreate expectedCallCreate = testCase.getCallCreateList().get(i);
if (resultCallCreate == null && expectedCallCreate != null) {
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);
continue;
}
boolean assertDestination = Arrays.equals(
expectedCallCreate.getDestination(),
resultCallCreate.getDestination());
if (!assertDestination) {
String output =
String.format("Call/Create destination is different. Expected: [ %s ], result: [ %s ]",
Hex.toHexString(expectedCallCreate.getDestination()),
Hex.toHexString(resultCallCreate.getDestination()));
logger.info(output);
results.add(output);
}
boolean assertData = Arrays.equals(
expectedCallCreate.getData(),
resultCallCreate.getData());
if (!assertData) {
String output =
String.format("Call/Create data is different. Expected: [ %s ], result: [ %s ]",
Hex.toHexString(expectedCallCreate.getData()),
Hex.toHexString(resultCallCreate.getData()));
logger.info(output);
results.add(output);
}
boolean assertGasLimit = Arrays.equals(
expectedCallCreate.getGasLimit(),
resultCallCreate.getGasLimit());
if (!assertGasLimit) {
String output =
String.format("Call/Create gasLimit is different. Expected: [ %s ], result: [ %s ]",
Hex.toHexString(expectedCallCreate.getGasLimit()),
Hex.toHexString(resultCallCreate.getGasLimit()));
logger.info(output);
results.add(output);
}
boolean assertValue = Arrays.equals(
expectedCallCreate.getValue(),
resultCallCreate.getValue());
if (!assertValue) {
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);
}
}
// assert out
byte[] expectedHReturn = testCase.getOut();
byte[] actualHReturn = EMPTY_BYTE_ARRAY;
if (program.getResult().getHReturn() != null) {
actualHReturn = program.getResult().getHReturn().array();
}
if (!Arrays.equals(expectedHReturn, actualHReturn)) {
String output =
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
BigInteger expectedGas = new BigInteger(1, testCase.getGas());
BigInteger actualGas = new BigInteger(1, 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)
*/
}
return results;
} finally {
// repository.close();
}
}
public org.ethereum.core.Transaction createTransaction(Transaction tx) {
byte[] nonceBytes = ByteUtil.longToBytes(tx.nonce);
byte[] gasPriceBytes = ByteUtil.longToBytes(tx.gasPrice);
byte[] gasBytes = tx.gasLimit;
byte[] valueBytes = ByteUtil.longToBytes(tx.value);
byte[] toAddr = tx.getTo();
byte[] data = tx.getData();
org.ethereum.core.Transaction transaction = new org.ethereum.core.Transaction(
nonceBytes, gasPriceBytes, gasBytes,
toAddr, valueBytes, data);
return transaction;
}
public RepositoryImpl loadRepository(RepositoryImpl track, Map<ByteArrayWrapper, AccountState> pre) {
/* 1. Store pre-exist accounts - Pre */
for (ByteArrayWrapper key : pre.keySet()) {
AccountState accountState = pre.get(key);
byte[] addr = key.getData();
track.addBalance(addr, new BigInteger(1, accountState.getBalance()));
track.setNonce(key.getData(), new BigInteger(1, accountState.getNonce()));
track.saveCode(addr, accountState.getCode());
for (DataWord storageKey : accountState.getStorage().keySet()) {
track.addStorageRow(addr, storageKey, accountState.getStorage().get(storageKey));
}
}
return track;
}
public ProgramTrace getTrace() {
return trace;
}
}

View File

@ -0,0 +1,35 @@
package org.ethereum.jsontestsuite;
import org.json.simple.JSONObject;
import org.json.simple.parser.ParseException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
/**
* @author Roman Mandeleil
* @since 10.07.2014
*/
public class TestSuite {
List<TestCase> testList = new ArrayList<>();
public TestSuite(JSONObject testCaseJSONObj) throws ParseException {
for (Object key : testCaseJSONObj.keySet()) {
Object testCaseJSON = testCaseJSONObj.get(key);
TestCase testCase = new TestCase(key.toString(), (JSONObject) testCaseJSON);
testList.add(testCase);
}
}
public List<TestCase> getAllTests(){
return testList;
}
public Iterator<TestCase> iterator() {
return testList.iterator();
}
}

View File

@ -0,0 +1,92 @@
package org.ethereum.jsontestsuite;
import org.json.simple.JSONObject;
import java.math.BigInteger;
import static org.ethereum.util.ByteUtil.toHexString;
/**
* @author Roman Mandeleil
* @since 28.06.2014
*/
public class Transaction {
byte[] data;
byte[] gasLimit;
long gasPrice;
long nonce;
byte[] secretKey;
byte[] to;
long value;
/* e.g.
"transaction" : {
"data" : "",
"gasLimit" : "10000",
"gasPrice" : "1",
"nonce" : "0",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
"value" : "100000"
}
*/
public Transaction(JSONObject callCreateJSON) {
String dataStr = callCreateJSON.get("data").toString();
String gasLimitStr = callCreateJSON.get("gasLimit").toString();
String gasPriceStr = callCreateJSON.get("gasPrice").toString();
String nonceStr = callCreateJSON.get("nonce").toString();
String secretKeyStr = callCreateJSON.get("secretKey").toString();
String toStr = callCreateJSON.get("to").toString();
String valueStr = callCreateJSON.get("value").toString();
this.data = Utils.parseData(dataStr);
this.gasLimit = !gasLimitStr.isEmpty() ? new BigInteger(gasLimitStr).toByteArray() : new byte[]{0};
this.gasPrice = Utils.parseLong(gasPriceStr);
this.nonce = Utils.parseLong(nonceStr);
this.secretKey = Utils.parseData(secretKeyStr);
this.to = Utils.parseData(toStr);
this.value = Utils.parseLong(valueStr);
}
public byte[] getData() {
return data;
}
public byte[] getGasLimit() {
return gasLimit;
}
public long getGasPrice() {
return gasPrice;
}
public long getNonce() {
return nonce;
}
public byte[] getSecretKey() {
return secretKey;
}
public byte[] getTo() {
return to;
}
public long getValue() {
return value;
}
@Override
public String toString() {
return "Transaction{" +
"data=" + toHexString(data) +
", gasLimit=" + gasLimit +
", gasPrice=" + gasPrice +
", nonce=" + nonce +
", secretKey=" + toHexString(secretKey) +
", to=" + toHexString(to) +
", value=" + value +
'}';
}
}

View File

@ -0,0 +1,23 @@
package org.ethereum.jsontestsuite;
import org.ethereum.util.ByteUtil;
import org.spongycastle.util.encoders.Hex;
/**
* @author Roman Mandeleil
* @since 15.12.2014
*/
public class Utils {
public static byte[] parseData(String data) {
if (data == null) return ByteUtil.EMPTY_BYTE_ARRAY;
if (data.startsWith("0x")) data = data.substring(2);
return Hex.decode(data);
}
public static long parseLong(String data) {
return data.equals("") ? 0 : Long.parseLong(data);
}
}