Add VM dumptrace in pretty format
This commit is contained in:
parent
45925d0791
commit
e106d2fdc7
|
@ -29,6 +29,7 @@ public class SystemProperties {
|
|||
private static Boolean DEFAULT_DB_RESET = false;
|
||||
private static Boolean DEFAULT_DUMP_FULL = false;
|
||||
private static String DEFAULT_DUMP_DIR = "dmp";
|
||||
private static String DEFAULT_DUMP_STYLE = "standard+";
|
||||
private static Integer DEFAULT_VMTRACE_BLOCK = 0;
|
||||
private static String DEFAULT_DATABASE_DIR = System.getProperty("user.dir");
|
||||
private static Boolean DEFAULT_DUMP_CLEAN_ON_RESTART = true;
|
||||
|
@ -152,11 +153,17 @@ public class SystemProperties {
|
|||
return prop.getProperty("dump.dir");
|
||||
}
|
||||
|
||||
public String dumpStyle() {
|
||||
if(prop.isEmpty()) return DEFAULT_DUMP_STYLE;
|
||||
return prop.getProperty("dump.style");
|
||||
}
|
||||
|
||||
public Integer dumpBlock() {
|
||||
if(prop.isEmpty()) return DEFAULT_VMTRACE_BLOCK;
|
||||
return Integer.parseInt(prop.getProperty("dump.block"));
|
||||
}
|
||||
|
||||
|
||||
public String databaseDir() {
|
||||
if(prop.isEmpty()) return DEFAULT_DATABASE_DIR;
|
||||
return prop.getProperty("database.dir");
|
||||
|
|
|
@ -32,7 +32,7 @@ import java.util.concurrent.CopyOnWriteArrayList;
|
|||
*/
|
||||
public class Block {
|
||||
|
||||
private static Logger logger = LoggerFactory.getLogger("block");
|
||||
private static final Logger logger = LoggerFactory.getLogger("block");
|
||||
|
||||
/* A scalar value equal to the mininum limit of gas expenditure per block */
|
||||
private static long MIN_GAS_LIMIT = 125000L;
|
||||
|
|
|
@ -96,8 +96,8 @@ public class Blockchain {
|
|||
if (block == null)
|
||||
return;
|
||||
|
||||
if (block.getNumber() == 12301)
|
||||
logger.debug("Block #12301");
|
||||
if (block.getNumber() == 12390)
|
||||
logger.debug("Block #12390");
|
||||
|
||||
// if it is the first block to add
|
||||
// make sure the parent is genesis
|
||||
|
@ -153,11 +153,14 @@ public class Blockchain {
|
|||
for (TransactionReceipt txr : block.getTxReceiptList()) {
|
||||
stateLogger.debug("apply block: [ {} ] tx: [ {} ] ", block.getNumber(), i);
|
||||
totalGasUsed += applyTransaction(block, txr.getTransaction());
|
||||
if(!Arrays.equals(this.repository.getWorldState().getRootHash(), txr.getPostTxState()))
|
||||
stateLogger.warn("TX: STATE CONFLICT {}..: {}", Hex.toHexString(txr.getTransaction().getHash()).substring(0, 8),
|
||||
Hex.toHexString(this.repository.getWorldState().getRootHash()));
|
||||
if(block.getNumber() >= CONFIG.traceStartBlock())
|
||||
repository.dumpState(block, totalGasUsed, i++, txr.getTransaction().getHash());
|
||||
if(!Arrays.equals(this.repository.getWorldState().getRootHash(), txr.getPostTxState())) {
|
||||
stateLogger.warn("TX: STATE CONFLICT {}..: {}", Hex.toHexString(txr.getTransaction().getHash()).substring(0, 8),
|
||||
Hex.toHexString(this.repository.getWorldState().getRootHash()));
|
||||
// repository.close();
|
||||
// System.exit(-1); // Don't continue
|
||||
}
|
||||
}
|
||||
|
||||
this.addReward(block);
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
package org.ethereum.trie;
|
||||
|
||||
import static java.util.Arrays.copyOfRange;
|
||||
import static org.spongycastle.util.Arrays.concatenate;
|
||||
import static org.ethereum.util.CompactEncoder.*;
|
||||
import static org.ethereum.util.ByteUtil.matchingNibbleLength;
|
||||
import static org.ethereum.util.CompactEncoder.binToNibbles;
|
||||
import static org.ethereum.util.CompactEncoder.packNibbles;
|
||||
import static org.ethereum.util.CompactEncoder.unpackToNibbles;
|
||||
import static org.spongycastle.util.Arrays.concatenate;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
|
||||
import org.ethereum.crypto.HashUtil;
|
||||
import org.ethereum.db.ByteArrayWrapper;
|
||||
|
@ -253,11 +254,9 @@ public class Trie implements TrieFacade {
|
|||
}
|
||||
|
||||
if (matchingLength == 0) {
|
||||
|
||||
// End of the chain, return
|
||||
return newHash;
|
||||
} else {
|
||||
|
||||
Object[] newNode = new Object[] { packNibbles(copyOfRange(key, 0, matchingLength)), newHash};
|
||||
return this.putToCache(newNode);
|
||||
}
|
||||
|
@ -300,7 +299,6 @@ public class Trie implements TrieFacade {
|
|||
} else {
|
||||
newNode = new Object[] {currentNode.get(0).asString(), hash};
|
||||
}
|
||||
|
||||
return this.putToCache(newNode);
|
||||
} else {
|
||||
return node;
|
||||
|
@ -337,7 +335,6 @@ public class Trie implements TrieFacade {
|
|||
} else {
|
||||
newNode = itemList;
|
||||
}
|
||||
|
||||
return this.putToCache(newNode);
|
||||
}
|
||||
}
|
||||
|
@ -449,7 +446,7 @@ public class Trie implements TrieFacade {
|
|||
* safe, the tree should not be modified during the
|
||||
* cleaning process.
|
||||
*/
|
||||
public void cleanCacheGarbage(){
|
||||
public void cleanCacheGarbage() {
|
||||
|
||||
CollectFullSetOfNodes collectAction = new CollectFullSetOfNodes();
|
||||
long startTime = System.currentTimeMillis();
|
||||
|
@ -460,15 +457,13 @@ public class Trie implements TrieFacade {
|
|||
Map<ByteArrayWrapper, Node> nodes = this.getCache().getNodes();
|
||||
Set<ByteArrayWrapper> toRemoveSet = new HashSet<>();
|
||||
|
||||
for (ByteArrayWrapper key : nodes.keySet()){
|
||||
|
||||
if (!hashSet.contains(key.getData())){
|
||||
|
||||
for (ByteArrayWrapper key : nodes.keySet()) {
|
||||
if (!hashSet.contains(key.getData())) {
|
||||
toRemoveSet.add(key);
|
||||
}
|
||||
}
|
||||
|
||||
for (ByteArrayWrapper key : toRemoveSet){
|
||||
for (ByteArrayWrapper key : toRemoveSet) {
|
||||
|
||||
this.getCache().delete(key.getData());
|
||||
|
||||
|
@ -476,29 +471,23 @@ public class Trie implements TrieFacade {
|
|||
logger.trace("Garbage collected node: [ {} ]",
|
||||
Hex.toHexString( key.getData() ));
|
||||
}
|
||||
|
||||
logger.info("Garbage collected node list, size: [ {} ]", toRemoveSet.size());
|
||||
logger.info("Garbage collection time: [ {}ms ]", System.currentTimeMillis() - startTime);
|
||||
}
|
||||
|
||||
|
||||
public void scanTree(byte[] hash , ScanAction scanAction){
|
||||
public void scanTree(byte[] hash, ScanAction scanAction) {
|
||||
|
||||
Value node = this.getCache().get(hash);
|
||||
if (node == null) return ;
|
||||
|
||||
if (node.isList()){
|
||||
if (node == null) return;
|
||||
|
||||
if (node.isList()) {
|
||||
List<Object> siblings = node.asList();
|
||||
if (siblings.size() == 2){
|
||||
if (siblings.size() == PAIR_SIZE) {
|
||||
Value val = new Value(siblings.get(1));
|
||||
if (val.isHashCode())
|
||||
scanTree(val.asBytes(), scanAction);
|
||||
|
||||
} else {
|
||||
|
||||
for (int j = 0; j < 17; ++j){
|
||||
|
||||
for (int j = 0; j < LIST_SIZE; ++j) {
|
||||
Value val = new Value(siblings.get(j));
|
||||
if (val.isHashCode())
|
||||
scanTree(val.asBytes(), scanAction);
|
||||
|
@ -508,26 +497,21 @@ public class Trie implements TrieFacade {
|
|||
}
|
||||
}
|
||||
|
||||
public String getTrieDump(){
|
||||
public String getTrieDump() {
|
||||
|
||||
String root = "";
|
||||
TraceAllNodes traceAction = new TraceAllNodes();
|
||||
this.scanTree(this.getRootHash(), traceAction);
|
||||
|
||||
if (this.getRoot() instanceof Value){
|
||||
|
||||
if (this.getRoot() instanceof Value) {
|
||||
root = "root: " + Hex.toHexString(getRootHash()) + " => " + this.getRoot() + "\n";
|
||||
} else{
|
||||
|
||||
} else {
|
||||
root = "root: " + Hex.toHexString(getRootHash()) + "\n";
|
||||
}
|
||||
|
||||
return root + traceAction.getOutput();
|
||||
}
|
||||
|
||||
|
||||
public interface ScanAction{
|
||||
|
||||
public interface ScanAction {
|
||||
public void doOnNode(byte[] hash, Value node);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -116,6 +116,24 @@ public class ByteUtil {
|
|||
return 0;
|
||||
return new BigInteger(1, b).intValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Turn nibbles to a pretty looking output string
|
||||
*
|
||||
* Example. [ 1, 2, 3, 4, 5 ] becomes '\x11\x23\x45'
|
||||
*
|
||||
* @param nibbles - getting byte of data [ 04 ] and turning
|
||||
* it to a '\x04' representation
|
||||
* @return pretty string of nibbles
|
||||
*/
|
||||
public static String nibblesToPrettyString(byte[] nibbles){
|
||||
StringBuffer buffer = new StringBuffer();
|
||||
for (byte nibble : nibbles) {
|
||||
String nibleString = Utils.oneByteToHexString(nibble);
|
||||
buffer.append("\\x" + nibleString);
|
||||
}
|
||||
return buffer.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the number of bytes need
|
||||
|
|
|
@ -51,25 +51,24 @@ public class CompactEncoder {
|
|||
private final static byte TERMINATOR = 16;
|
||||
private final static Map<Character, Byte> hexMap = new HashMap<>();
|
||||
static {
|
||||
hexMap.put('0', (byte)0);
|
||||
hexMap.put('1', (byte)1);
|
||||
hexMap.put('2', (byte)2);
|
||||
hexMap.put('3', (byte)3);
|
||||
hexMap.put('4', (byte)4);
|
||||
hexMap.put('5', (byte)5);
|
||||
hexMap.put('6', (byte)6);
|
||||
hexMap.put('7', (byte)7);
|
||||
hexMap.put('8', (byte)8);
|
||||
hexMap.put('9', (byte)9);
|
||||
hexMap.put('a', (byte)10);
|
||||
hexMap.put('b', (byte)11);
|
||||
hexMap.put('c', (byte)12);
|
||||
hexMap.put('d', (byte)13);
|
||||
hexMap.put('e', (byte)14);
|
||||
hexMap.put('f', (byte)15);
|
||||
hexMap.put('0', (byte)0x0);
|
||||
hexMap.put('1', (byte)0x1);
|
||||
hexMap.put('2', (byte)0x2);
|
||||
hexMap.put('3', (byte)0x3);
|
||||
hexMap.put('4', (byte)0x4);
|
||||
hexMap.put('5', (byte)0x5);
|
||||
hexMap.put('6', (byte)0x6);
|
||||
hexMap.put('7', (byte)0x7);
|
||||
hexMap.put('8', (byte)0x8);
|
||||
hexMap.put('9', (byte)0x9);
|
||||
hexMap.put('a', (byte)0xa);
|
||||
hexMap.put('b', (byte)0xb);
|
||||
hexMap.put('c', (byte)0xc);
|
||||
hexMap.put('d', (byte)0xd);
|
||||
hexMap.put('e', (byte)0xe);
|
||||
hexMap.put('f', (byte)0xf);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Pack nibbles to binary
|
||||
*
|
||||
|
@ -94,7 +93,7 @@ public class CompactEncoder {
|
|||
}
|
||||
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
|
||||
for (int i = 0; i < nibbles.length; i += 2) {
|
||||
buffer.write( 16*nibbles[i] + nibbles[i+1] );
|
||||
buffer.write(16*nibbles[i] + nibbles[i+1]);
|
||||
}
|
||||
return buffer.toByteArray();
|
||||
}
|
||||
|
@ -140,27 +139,6 @@ public class CompactEncoder {
|
|||
for (byte b : hexEncoded) {
|
||||
slice.put(hexMap.get((char)b));
|
||||
}
|
||||
|
||||
return slice.array();
|
||||
}
|
||||
|
||||
/**
|
||||
* turn nibbles to a nice good looking output string
|
||||
*
|
||||
* @param nibbles - getting byte of data [ 04 ] and turning
|
||||
* it to a '\x04' representation
|
||||
* @return
|
||||
*/
|
||||
public static String nibblesToPrettyString(byte[] nibbles){
|
||||
|
||||
StringBuffer buffer = new StringBuffer();
|
||||
for (byte nibble : nibbles){
|
||||
|
||||
String nibleString = Utils.oneByteToHexString(nibble);
|
||||
|
||||
buffer.append("\\x" + nibleString);
|
||||
}
|
||||
|
||||
return buffer.toString();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
package org.ethereum.util;
|
||||
|
||||
import java.lang.reflect.Array;
|
||||
import java.math.BigInteger;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
@ -155,7 +154,6 @@ public class Value {
|
|||
}
|
||||
|
||||
for (int i = 0; i < data.length; ++i){
|
||||
|
||||
if (data[i] > 32 && data[i] < 126) ++readableChars;
|
||||
}
|
||||
|
||||
|
@ -171,14 +169,14 @@ public class Value {
|
|||
int hexChars = 0;
|
||||
byte[] data = (byte[])value;
|
||||
|
||||
for (int i = 0; i < data.length; ++i){
|
||||
for (int i = 0; i < data.length; ++i) {
|
||||
|
||||
if ((data[i] >= 48 && data[i] <= 57) ||
|
||||
(data[i] >= 97 && data[i] <= 102)
|
||||
) ++hexChars;
|
||||
}
|
||||
if ((data[i] >= 48 && data[i] <= 57)
|
||||
|| (data[i] >= 97 && data[i] <= 102))
|
||||
++hexChars;
|
||||
}
|
||||
|
||||
if ((double)hexChars / (double)data.length > 0.9)
|
||||
if ((double) hexChars / (double) data.length > 0.9)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
|
@ -212,23 +210,23 @@ public class Value {
|
|||
return 0;
|
||||
}
|
||||
|
||||
public String toString(){
|
||||
public String toString() {
|
||||
|
||||
StringBuffer buffer = new StringBuffer();
|
||||
|
||||
if (isList()){
|
||||
if (isList()) {
|
||||
|
||||
Object[] list = (Object[])value;
|
||||
Object[] list = (Object[]) value;
|
||||
|
||||
// special case - key/value node
|
||||
if (list.length == 2){
|
||||
if (list.length == 2) {
|
||||
|
||||
buffer.append("[ ");
|
||||
|
||||
Value key = new Value(list[0]);
|
||||
|
||||
byte[] keyNibbles = CompactEncoder.binToNibblesNoTerminator(key.asBytes());
|
||||
String keyString = CompactEncoder.nibblesToPrettyString(keyNibbles);
|
||||
String keyString = ByteUtil.nibblesToPrettyString(keyNibbles);
|
||||
buffer.append(keyString);
|
||||
|
||||
buffer.append(",");
|
||||
|
@ -239,83 +237,60 @@ public class Value {
|
|||
buffer.append(" ]");
|
||||
return buffer.toString();
|
||||
}
|
||||
|
||||
buffer.append(" [");
|
||||
|
||||
for (int i = 0; i < list.length; ++i){
|
||||
|
||||
Value val = new Value(list[i]);
|
||||
|
||||
if (val.isString() || val.isEmpty()){
|
||||
|
||||
buffer.append("'").
|
||||
append(val.toString())
|
||||
.append("'");
|
||||
buffer.append("'").append(val.toString()).append("'");
|
||||
} else {
|
||||
|
||||
buffer.append(val.toString());
|
||||
}
|
||||
|
||||
if (i < list.length - 1)
|
||||
buffer.append(", ");
|
||||
}
|
||||
buffer.append("] ");
|
||||
|
||||
return buffer.toString();
|
||||
} else if (isEmpty()){
|
||||
} else if (isEmpty()) {
|
||||
return "";
|
||||
} else if (isBytes()){
|
||||
} else if (isBytes()) {
|
||||
|
||||
StringBuffer output = new StringBuffer();
|
||||
if (isHashCode()) {
|
||||
output.append(Hex.toHexString(asBytes()));
|
||||
}else if (isReadbleString()){
|
||||
|
||||
} else if (isReadbleString()) {
|
||||
output.append("'");
|
||||
for (byte oneByte : asBytes()){
|
||||
if (oneByte < 16){
|
||||
for (byte oneByte : asBytes()) {
|
||||
if (oneByte < 16) {
|
||||
output.append("\\x").append(Utils.oneByteToHexString(oneByte));
|
||||
} else {
|
||||
|
||||
output.append( Character.valueOf((char)oneByte) );
|
||||
}
|
||||
}
|
||||
|
||||
output.append("'");
|
||||
return output.toString();
|
||||
}
|
||||
|
||||
return Hex.toHexString(this.asBytes());
|
||||
} else if (isString()){
|
||||
|
||||
return asString();
|
||||
}
|
||||
|
||||
return "what the fuck";
|
||||
return "Unexpected type";
|
||||
}
|
||||
|
||||
|
||||
|
||||
public int countYourBranchNodes(){
|
||||
|
||||
if (this.isList()){
|
||||
|
||||
List<Object> objList = this.asList();
|
||||
|
||||
int i = 0;
|
||||
for (Object obj : objList){
|
||||
|
||||
i += (new Value(obj)).countYourBranchNodes();
|
||||
}
|
||||
|
||||
return i;
|
||||
} else if (this.isBytes()){
|
||||
|
||||
this.asBytes();
|
||||
|
||||
}
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -265,6 +265,11 @@ public class DataWord implements Comparable<DataWord> {
|
|||
public String toString() {
|
||||
return Hex.toHexString(data);
|
||||
}
|
||||
|
||||
public String shortHex() {
|
||||
String hexValue = Hex.toHexString(getNoLeadZeroesData()).toUpperCase();
|
||||
return "0x" + hexValue.replaceFirst("^0+(?!$)", "");
|
||||
}
|
||||
|
||||
public DataWord clone() {
|
||||
return new DataWord(Arrays.clone(data));
|
||||
|
|
|
@ -11,7 +11,10 @@ import org.spongycastle.util.encoders.Hex;
|
|||
|
||||
import java.math.BigInteger;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Stack;
|
||||
|
||||
/**
|
||||
|
@ -185,7 +188,7 @@ public class Program {
|
|||
int offset = offsetData.intValue();
|
||||
int size = sizeData.intValue();
|
||||
byte[] chunk = new byte[size];
|
||||
allocateMemory(offset, chunk);
|
||||
allocateMemory(offset, new byte[size]);
|
||||
|
||||
if (memory != null) {
|
||||
if (memory.limit() < offset + size) size = memory.limit() - offset;
|
||||
|
@ -424,8 +427,12 @@ public class Program {
|
|||
if (retSize > allocSize) {
|
||||
byte[] outArray = Arrays.copyOf(buffer.array(), allocSize);
|
||||
this.memorySave(outArray, buffer.array());
|
||||
} else {
|
||||
} else if (retSize == 0 || retSize == allocSize){
|
||||
this.memorySave(outDataOffs.getData(), buffer.array());
|
||||
} else {
|
||||
byte[] outArray = new byte[allocSize];
|
||||
System.arraycopy(buffer.array(), 0, outArray, 0, retSize);
|
||||
this.memorySave(outDataOffs.getData(), outArray);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -562,6 +569,34 @@ public class Program {
|
|||
public void setRuntimeFailure(RuntimeException e) {
|
||||
result.setException(e);
|
||||
}
|
||||
|
||||
public String memoryToString() {
|
||||
StringBuilder memoryData = new StringBuilder();
|
||||
StringBuilder firstLine = new StringBuilder();
|
||||
StringBuilder secondLine = new StringBuilder();
|
||||
for (int i = 0; memory != null && i < memory.limit(); ++i) {
|
||||
|
||||
byte value = memory.get(i);
|
||||
// Check if value is ASCII
|
||||
// (should be until 0x7e - but using 0x7f
|
||||
// to be compatible with cpp-ethereum)
|
||||
// See: https://github.com/ethereum/cpp-ethereum/issues/299
|
||||
String character = ((byte)0x20 <= value && value <= (byte)0x7f) ? new String(new byte[]{value}) : "?";
|
||||
firstLine.append(character).append("");
|
||||
secondLine.append(Utils.oneByteToHexString(value)).append(" ");
|
||||
|
||||
if ((i + 1) % 8 == 0) {
|
||||
String tmp = String.format("%4s", Integer.toString(i - 7, 16)).replace(" ", "0");
|
||||
memoryData.append("").append(tmp).append(" ");
|
||||
memoryData.append(firstLine).append(" ");
|
||||
memoryData.append(secondLine);
|
||||
if (i+1 < memory.limit()) memoryData.append("\n");
|
||||
firstLine.setLength(0);
|
||||
secondLine.setLength(0);
|
||||
}
|
||||
}
|
||||
return memoryData.toString();
|
||||
}
|
||||
|
||||
public void fullTrace() {
|
||||
|
||||
|
@ -577,7 +612,9 @@ public class Program {
|
|||
ContractDetails contractDetails = this.result.getRepository().
|
||||
getContractDetails(this.programAddress.getLast20Bytes());
|
||||
StringBuilder storageData = new StringBuilder();
|
||||
for (DataWord key : contractDetails.getStorage().keySet()) {
|
||||
List<DataWord> storageKeys = new ArrayList<>(contractDetails.getStorage().keySet());
|
||||
Collections.sort((List<DataWord>) storageKeys);
|
||||
for (DataWord key : storageKeys) {
|
||||
storageData.append(" ").append(key).append(" -> ").
|
||||
append(contractDetails.getStorage().get(key)).append("\n");
|
||||
}
|
||||
|
@ -625,8 +662,6 @@ public class Program {
|
|||
invokeData.getGas().longValue(),
|
||||
getGas().longValue());
|
||||
|
||||
|
||||
|
||||
StringBuilder globalOutput = new StringBuilder("\n");
|
||||
if (stackData.length() > 0) stackData.append("\n");
|
||||
|
||||
|
|
|
@ -64,12 +64,17 @@ public class VM {
|
|||
private Logger logger = LoggerFactory.getLogger("VM");
|
||||
private Logger dumpLogger = LoggerFactory.getLogger("dump");
|
||||
private static BigInteger _32_ = BigInteger.valueOf(32);
|
||||
private static String logString = "[{}]\t Op: [{}] Gas: [{}]\t Deep: [{}] Hint: [{}]";
|
||||
private static String logString = "[{}]\t Op: [{}] Gas: [{}] Deep: [{}] Hint: [{}]";
|
||||
|
||||
private static BigInteger MAX_GAS = BigInteger.valueOf(Long.MAX_VALUE);
|
||||
|
||||
/* Keeps track of the number of steps performed in this VM */
|
||||
private int vmCounter = 0;
|
||||
|
||||
public void step(Program program) {
|
||||
|
||||
program.fullTrace();
|
||||
|
||||
try {
|
||||
OpCode op = OpCode.code(program.getCurrentOp());
|
||||
program.setLastOp(op.val());
|
||||
|
@ -79,92 +84,96 @@ public class VM {
|
|||
Stack<DataWord> stack = program.getStack();
|
||||
|
||||
String hint = "";
|
||||
long callGas = 0, memWords = 0; // parameters for logging
|
||||
long gasCost = GasCost.STEP;
|
||||
long gasBefore = program.getGas().longValue();
|
||||
int stepBefore = program.getPC();
|
||||
|
||||
// Log debugging line for VM
|
||||
if(program.getNumber().intValue() == CONFIG.dumpBlock())
|
||||
this.dumpLine(op.val(), program);
|
||||
|
||||
// Calculate fees and spend gas
|
||||
switch (op) {
|
||||
case STOP: case SUICIDE:
|
||||
// The ops that doesn't charged by step, or
|
||||
// charged in the following section
|
||||
// The ops that don't charge by step
|
||||
gasCost = GasCost.STOP;
|
||||
break;
|
||||
case SSTORE:
|
||||
// for gas calculations [YP 9.2]
|
||||
DataWord newValue = stack.get(stack.size()-2);
|
||||
DataWord oldValue = program.storageLoad(stack.peek());
|
||||
if (oldValue == null && !newValue.isZero()) {
|
||||
program.spendGas(GasCost.SSTORE * 2, op.name());
|
||||
gasCost = GasCost.SSTORE * 2;
|
||||
} else if (oldValue != null && newValue.isZero()) {
|
||||
program.spendGas(GasCost.SSTORE * 0, op.name());
|
||||
gasCost = GasCost.SSTORE * 0;
|
||||
} else
|
||||
program.spendGas(GasCost.SSTORE, op.name());
|
||||
gasCost = GasCost.SSTORE;
|
||||
break;
|
||||
case SLOAD:
|
||||
program.spendGas(GasCost.SLOAD, op.name());
|
||||
gasCost = GasCost.SLOAD;
|
||||
break;
|
||||
case BALANCE:
|
||||
program.spendGas(GasCost.BALANCE, op.name());
|
||||
gasCost = GasCost.BALANCE;
|
||||
break;
|
||||
|
||||
// These all operate on memory and therefore potentially expand it:
|
||||
case MSTORE:
|
||||
newMemSize = stack.peek().value().add(BigInteger.valueOf(32));
|
||||
program.spendGas(GasCost.STEP, op.name());
|
||||
break;
|
||||
case MSTORE8:
|
||||
newMemSize = stack.peek().value().add(BigInteger.ONE);
|
||||
program.spendGas(GasCost.STEP, op.name());
|
||||
break;
|
||||
case MLOAD:
|
||||
newMemSize = stack.peek().value().add(BigInteger.valueOf(32));
|
||||
program.spendGas(GasCost.STEP, op.name());
|
||||
break;
|
||||
case RETURN:
|
||||
newMemSize = stack.peek().value().add(stack.get(stack.size()-2).value());
|
||||
program.spendGas(GasCost.STEP, op.name());
|
||||
break;
|
||||
case SHA3:
|
||||
program.spendGas(GasCost.SHA3, op.name());
|
||||
gasCost = GasCost.SHA3;
|
||||
newMemSize = stack.peek().value().add(stack.get(stack.size()-2).value());
|
||||
break;
|
||||
case CALLDATACOPY:
|
||||
newMemSize = stack.peek().value().add(stack.get(stack.size()-3).value());
|
||||
program.spendGas(GasCost.STEP, op.name());
|
||||
break;
|
||||
case CODECOPY:
|
||||
newMemSize = stack.peek().value().add(stack.get(stack.size()-3).value());
|
||||
program.spendGas(GasCost.STEP, op.name());
|
||||
break;
|
||||
case CALL:
|
||||
program.spendGas(GasCost.CALL, op.name());
|
||||
BigInteger callGas = stack.get(stack.size()-1).value();
|
||||
if(callGas.compareTo(program.getGas().value()) == 1) {
|
||||
gasCost = GasCost.CALL;
|
||||
BigInteger callGasWord = stack.get(stack.size()-1).value();
|
||||
if(callGasWord.compareTo(program.getGas().value()) == 1) {
|
||||
throw program.new OutOfGasException();
|
||||
}
|
||||
callGas = callGasWord.longValue();
|
||||
// Casting to long (causing overflow) as workaround for PoC5 - should be removed for PoC6
|
||||
long x = stack.get(stack.size()-6).value().add(stack.get(stack.size()-7).value()).longValue();
|
||||
long y = stack.get(stack.size()-4).value().add(stack.get(stack.size()-5).value()).longValue();
|
||||
newMemSize = BigInteger.valueOf(Math.max(x, y));
|
||||
break;
|
||||
case CREATE:
|
||||
program.spendGas(GasCost.CREATE, op.name());
|
||||
gasCost = GasCost.CREATE;
|
||||
newMemSize = stack.get(stack.size()-2).value().add(stack.get(stack.size()-3).value());
|
||||
break;
|
||||
default:
|
||||
program.spendGas(GasCost.STEP, op.name());
|
||||
break;
|
||||
}
|
||||
program.spendGas(gasCost, op.name());
|
||||
|
||||
if(newMemSize.compareTo(MAX_GAS) == 1) {
|
||||
throw program.new OutOfGasException();
|
||||
}
|
||||
// memory gas calc
|
||||
long memoryUsage = (newMemSize.longValue() + 31) / 32 * 32;
|
||||
if (memoryUsage > oldMemSize)
|
||||
program.spendGas(GasCost.MEMORY * ((memoryUsage - oldMemSize) / 32), op.name() + " (memory usage)");
|
||||
|
||||
// memory gas calc
|
||||
long memoryUsage = (newMemSize.longValue() + 31) / 32 * 32;
|
||||
if (memoryUsage > oldMemSize) {
|
||||
memWords = (memoryUsage - oldMemSize) / 32;
|
||||
long memGas = GasCost.MEMORY * memWords;
|
||||
program.spendGas(memGas, op.name() + " (memory usage)");
|
||||
gasCost += memGas;
|
||||
}
|
||||
|
||||
// Log debugging line for VM
|
||||
if(program.getNumber().intValue() == CONFIG.dumpBlock())
|
||||
this.dumpLine(op, gasBefore, gasCost+callGas, memWords, program);
|
||||
|
||||
// Execute operation
|
||||
switch (op) {
|
||||
/**
|
||||
|
@ -492,7 +501,7 @@ public class VM {
|
|||
DataWord callValue = program.getCallValue();
|
||||
|
||||
if (logger.isInfoEnabled())
|
||||
hint = "value: " + callValue.toString();
|
||||
hint = "value: " + callValue;
|
||||
|
||||
program.stackPush(callValue);
|
||||
program.step();
|
||||
|
@ -502,7 +511,7 @@ public class VM {
|
|||
DataWord value = program.getDataValue(dataOffs);
|
||||
|
||||
if (logger.isInfoEnabled())
|
||||
hint = "data: " + value.toString();
|
||||
hint = "data: " + value;
|
||||
|
||||
program.stackPush(value);
|
||||
program.step();
|
||||
|
@ -677,7 +686,7 @@ public class VM {
|
|||
DataWord val = program.storageLoad(key);
|
||||
|
||||
if (logger.isInfoEnabled())
|
||||
hint = "key: " + key + " value: " + val;
|
||||
hint = "key: " + key + " value: " + val;
|
||||
|
||||
if (val == null) {
|
||||
val = key.and(DataWord.ZERO);
|
||||
|
@ -784,12 +793,17 @@ public class VM {
|
|||
|
||||
DataWord outDataOffs = program.stackPop();
|
||||
DataWord outDataSize = program.stackPop();
|
||||
|
||||
if (logger.isInfoEnabled())
|
||||
|
||||
if (logger.isInfoEnabled()) {
|
||||
hint = "addr: " + Hex.toHexString(toAddress.getLast20Bytes())
|
||||
+ " gas: " + gas.shortHex()
|
||||
+ " inOff: " + inDataOffs.shortHex()
|
||||
+ " inSize: " + inDataSize.shortHex();
|
||||
logger.info(logString, program.getPC(),
|
||||
String.format("%-12s", op.name()),
|
||||
program.getGas().value(),
|
||||
program.invokeData.getCallDeep(), hint);
|
||||
}
|
||||
|
||||
program.callToAddress(gas, toAddress, value, inDataOffs, inDataSize, outDataOffs, outDataSize);
|
||||
|
||||
|
@ -803,7 +817,9 @@ public class VM {
|
|||
program.setHReturn(hReturn);
|
||||
|
||||
if (logger.isInfoEnabled())
|
||||
hint = "data: " + Hex.toHexString(hReturn.array());
|
||||
hint = "data: " + Hex.toHexString(hReturn.array())
|
||||
+ " offset: " + offset.value()
|
||||
+ " size: " + size.value();
|
||||
|
||||
program.step();
|
||||
program.stop();
|
||||
|
@ -818,18 +834,17 @@ public class VM {
|
|||
program.stop();
|
||||
} break;
|
||||
default:{
|
||||
throw new IllegalOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
if (logger.isInfoEnabled() && !op.equals(CALL)
|
||||
&& !op.equals(CREATE))
|
||||
logger.info(logString, stepBefore, String.format("%-12s", op.name()), program.getGas().longValue(),
|
||||
logger.info(logString, stepBefore, String.format("%-12s",
|
||||
op.name()), program.getGas().longValue(),
|
||||
program.invokeData.getCallDeep(), hint);
|
||||
|
||||
program.fullTrace();
|
||||
|
||||
|
||||
// program.fullTrace();
|
||||
|
||||
vmCounter++;
|
||||
} catch (RuntimeException e) {
|
||||
if(e instanceof OutOfGasException)
|
||||
logger.warn("OutOfGasException occurred", e);
|
||||
|
@ -858,28 +873,69 @@ public class VM {
|
|||
}
|
||||
}
|
||||
|
||||
private void dumpLine(byte op, Program program) {
|
||||
switch (OpCode.code(op)) {
|
||||
case STOP: case RETURN: case SUICIDE:
|
||||
|
||||
ContractDetails details = program.getResult().getRepository()
|
||||
/*
|
||||
* Dumping the VM state at the current operation in various styles
|
||||
* - standard Not Yet Implemented
|
||||
* - standard+ (owner address, program counter, operation, gas left)
|
||||
* - pretty (stack, memory, storage, level, contract,
|
||||
* vmCounter, internalSteps, operation
|
||||
gasBefore, gasCost, memWords)
|
||||
*/
|
||||
private void dumpLine(OpCode op, long gasBefore, long gasCost, long memWords, Program program) {
|
||||
if(CONFIG.dumpStyle().equals("standard+")) {
|
||||
switch (op) {
|
||||
case STOP: case RETURN: case SUICIDE:
|
||||
|
||||
ContractDetails details = program.getResult().getRepository()
|
||||
.getContractDetails(program.getOwnerAddress().getLast20Bytes());
|
||||
List<DataWord> storageKeys = new ArrayList<>(details.getStorage().keySet());
|
||||
Collections.sort((List<DataWord>) storageKeys);
|
||||
|
||||
for (DataWord key : storageKeys) {
|
||||
dumpLogger.trace("{} {}",
|
||||
Hex.toHexString(key.getNoLeadZeroesData()),
|
||||
Hex.toHexString(details.getStorage().get(key).getNoLeadZeroesData()));
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
String addressString = Hex.toHexString(program.getOwnerAddress().getLast20Bytes());
|
||||
String pcString = Hex.toHexString(new DataWord(program.getPC()).getNoLeadZeroesData());
|
||||
String opString = Hex.toHexString(new byte[]{op.val()});
|
||||
String gasString = Hex.toHexString(program.getGas().getNoLeadZeroesData());
|
||||
|
||||
dumpLogger.trace("{} {} {} {}", addressString, pcString, opString, gasString);
|
||||
} else if(CONFIG.dumpStyle().equals("pretty")) {
|
||||
dumpLogger.trace(" STACK");
|
||||
for (DataWord item : program.getStack()) {
|
||||
dumpLogger.trace("{}", item);
|
||||
}
|
||||
dumpLogger.trace(" MEMORY");
|
||||
String memoryString = program.memoryToString();
|
||||
if(!"".equals(memoryString))
|
||||
dumpLogger.trace("{}", memoryString);
|
||||
|
||||
dumpLogger.trace(" STORAGE");
|
||||
ContractDetails details = program.getResult().getRepository()
|
||||
.getContractDetails(program.getOwnerAddress().getLast20Bytes());
|
||||
List<DataWord> storageKeys = new ArrayList<>(details.getStorage().keySet());
|
||||
Collections.sort((List<DataWord>) storageKeys);
|
||||
|
||||
for (DataWord key : storageKeys) {
|
||||
dumpLogger.info("{} {}",
|
||||
Hex.toHexString(key.getNoLeadZeroesData()),
|
||||
Hex.toHexString(details.getStorage().get(key).getNoLeadZeroesData()));
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
String addressString = Hex.toHexString(program.getOwnerAddress().getLast20Bytes());
|
||||
String pcString = Hex.toHexString(new DataWord(program.getPC()).getNoLeadZeroesData());
|
||||
String opString = Hex.toHexString(new byte[]{op});
|
||||
String gasString = Hex.toHexString(program.getGas().getNoLeadZeroesData());
|
||||
|
||||
dumpLogger.info("{} {} {} {}", addressString, pcString, opString, gasString);
|
||||
List<DataWord> storageKeys = new ArrayList<>(details.getStorage().keySet());
|
||||
Collections.sort((List<DataWord>) storageKeys);
|
||||
|
||||
for (DataWord key : storageKeys) {
|
||||
dumpLogger.trace("{}: {}",
|
||||
key.shortHex(),
|
||||
details.getStorage().get(key).shortHex());
|
||||
}
|
||||
|
||||
int level = program.invokeData.getCallDeep();
|
||||
String contract = Hex.toHexString(program.getOwnerAddress().getLast20Bytes());
|
||||
String internalSteps = String.format("%4s", Integer.toHexString(program.getPC())).replace(' ', '0').toUpperCase();
|
||||
dumpLogger.trace("{} | {} | #{} | {} : {} | {} | -{} | {}x32",
|
||||
level, contract, vmCounter, internalSteps, op,
|
||||
gasBefore, gasCost, memWords);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
private class IllegalOperationException extends RuntimeException {}
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@ log4j.logger.java.nio = ERROR
|
|||
log4j.logger.io.netty = ERROR
|
||||
log4j.logger.wire = ERROR
|
||||
log4j.logger.wallet = ERROR
|
||||
log4j.logger.VM = DEBUG
|
||||
log4j.logger.VM = TRACE
|
||||
log4j.logger.dump = OFF
|
||||
log4j.logger.main = INFO
|
||||
log4j.logger.trie = ERROR
|
||||
|
|
|
@ -1,11 +1,18 @@
|
|||
# Root logger option
|
||||
log4j.rootLogger=DEBUG, stdout, file
|
||||
log4j.logger.dump=TRACE, DUMP
|
||||
|
||||
# Direct log messages to stdout
|
||||
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
|
||||
log4j.appender.stdout.Target=System.out
|
||||
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
|
||||
log4j.appender.stdout.layout.ConversionPattern= %d{HH:mm:ss} [%c{1}] %m%n
|
||||
log4j.appender.stdout.layout.ConversionPattern=%d{HH:mm:ss} [%c{1}] %m%n
|
||||
log4j.appender.stdout.Threshold=DEBUG
|
||||
|
||||
# Direct log messages to stdout
|
||||
log4j.appender.DUMP=org.apache.log4j.ConsoleAppender
|
||||
log4j.appender.DUMP.Target=System.out
|
||||
log4j.appender.DUMP.layout=org.apache.log4j.PatternLayout
|
||||
|
||||
log4j.appender.file=org.apache.log4j.rolling.RollingFileAppender
|
||||
log4j.appender.file.layout=org.apache.log4j.PatternLayout
|
||||
|
@ -14,7 +21,7 @@ log4j.appender.file.RollingPolicy=org.apache.log4j.rolling.TimeBasedRollingPolic
|
|||
log4j.appender.file.RollingPolicy.FileNamePattern=./logs/ethereum_%d{yyyy-MM-dd}_h%d{HH}.log
|
||||
|
||||
# filter noisy classes
|
||||
log4j.logger.org.ethereum.core = ERROR
|
||||
log4j.logger.block = ERROR
|
||||
log4j.logger.wallet = ERROR
|
||||
log4j.logger.net = ERROR
|
||||
log4j.logger.db = ERROR
|
||||
|
|
|
@ -11,7 +11,7 @@ peer.discovery.ip.list = 185.43.109.23:30303, \
|
|||
54.72.69.180:30303, \
|
||||
54.201.28.117:30303, \
|
||||
70.29.74.8:7
|
||||
|
||||
#peer.discovery.ip.list = 127.0.0.1:30303
|
||||
|
||||
# active peer ip and port
|
||||
# that is the peer through
|
||||
|
@ -32,6 +32,10 @@ peer.discovery.ip.list = 185.43.109.23:30303, \
|
|||
peer.active.ip = 185.43.109.23
|
||||
peer.active.port = 30303
|
||||
|
||||
# Localhost
|
||||
#peer.active.ip = 127.0.0.1
|
||||
#peer.active.port = 30303
|
||||
|
||||
#peer.active.ip = 54.72.69.180
|
||||
#peer.active.port = 30303
|
||||
|
||||
|
@ -96,10 +100,16 @@ coinbase.secret = monkey
|
|||
# all the state will be dumped
|
||||
# in JSON form to [dump.dir]
|
||||
# if [dump.full] = true
|
||||
# posible values [true/false]
|
||||
# possible values [true/false]
|
||||
dump.full = false
|
||||
dump.dir = dmp
|
||||
|
||||
# This defines the vmtrace dump
|
||||
# to the console and the style
|
||||
# -1 for no block trace
|
||||
# styles: [pretty/standard+] (default: standard+)
|
||||
dump.block = -1
|
||||
dump.style = pretty
|
||||
|
||||
# clean the dump dir each start
|
||||
dump.clean.on.restart = true
|
||||
|
|
|
@ -6,22 +6,20 @@ import static org.junit.Assert.assertNotEquals;
|
|||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.math.BigInteger;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.URL;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.util.*;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
|
||||
import org.ethereum.core.AccountState;
|
||||
import org.ethereum.crypto.HashUtil;
|
||||
import org.ethereum.db.ByteArrayWrapper;
|
||||
import org.ethereum.db.DatabaseImpl;
|
||||
import org.ethereum.util.CompactEncoder;
|
||||
import org.ethereum.util.Value;
|
||||
import org.iq80.leveldb.DBIterator;
|
||||
import org.json.simple.JSONArray;
|
||||
import org.json.simple.JSONObject;
|
||||
import org.json.simple.parser.JSONParser;
|
||||
|
@ -520,53 +518,57 @@ public class TrieTest {
|
|||
trie.update("te", "testy");
|
||||
assertEquals("8452568af70d8d140f58d941338542f645fcca50094b20f3c3d8c3df49337928", Hex.toHexString(trie.getRootHash()));
|
||||
}
|
||||
|
||||
private final String randomDictionary = "spinneries, archipenko, prepotency, herniotomy, preexpress, relaxative, insolvably, debonnaire, apophysate, virtuality, cavalryman, utilizable, diagenesis, vitascopic, governessy, abranchial, cyanogenic, gratulated, signalment, predicable, subquality, crystalize, prosaicism, oenologist, repressive, impanelled, cockneyism, bordelaise, compigne, konstantin, predicated, unsublimed, hydrophane, phycomyces, capitalise, slippingly, untithable, unburnable, deoxidizer, misteacher, precorrect, disclaimer, solidified, neuraxitis, caravaning, betelgeuse, underprice, uninclosed, acrogynous, reirrigate, dazzlingly, chaffiness, corybantes, intumesced, intentness, superexert, abstrusely, astounding, pilgrimage, posttarsal, prayerless, nomologist, semibelted, frithstool, unstinging, ecalcarate, amputating, megascopic, graphalloy, platteland, adjacently, mingrelian, valentinus, appendical, unaccurate, coriaceous, waterworks, sympathize, doorkeeper, overguilty, flaggingly, admonitory, aeriferous, normocytic, parnellism, catafalque, odontiasis, apprentice, adulterous, mechanisma, wilderness, undivorced, reinterred, effleurage, pretrochal, phytogenic, swirlingly, herbarized, unresolved, classifier, diosmosing, microphage, consecrate, astarboard, predefying, predriving, lettergram, ungranular, overdozing, conferring, unfavorite, peacockish, coinciding, erythraeum, freeholder, zygophoric, imbitterer, centroidal, appendixes, grayfishes, enological, indiscreet, broadcloth, divulgated, anglophobe, stoopingly, bibliophil, laryngitis, separatist, estivating, bellarmine, greasiness, typhlology, xanthation, mortifying, endeavorer, aviatrices, unequalise, metastatic, leftwinger, apologizer, quatrefoil, nonfouling, bitartrate, outchiding, undeported, poussetted, haemolysis, asantehene, montgomery, unjoinable, cedarhurst, unfastener, nonvacuums, beauregard, animalized, polyphides, cannizzaro, gelatinoid, apologised, unscripted, tracheidal, subdiscoid, gravelling, variegated, interabang, inoperable, immortelle, laestrygon, duplicatus, proscience, deoxidised, manfulness, channelize, nondefense, ectomorphy, unimpelled, headwaiter, hexaemeric, derivation, prelexical, limitarian, nonionized, prorefugee, invariably, patronizer, paraplegia, redivision, occupative, unfaceable, hypomnesia, psalterium, doctorfish, gentlefolk, overrefine, heptastich, desirously, clarabelle, uneuphonic, autotelism, firewarden, timberjack, fumigation, drainpipes, spathulate, novelvelle, bicorporal, grisliness, unhesitant, supergiant, unpatented, womanpower, toastiness, multichord, paramnesia, undertrick, contrarily, neurogenic, gunmanship, settlement, brookville, gradualism, unossified, villanovan, ecospecies, organising, buckhannon, prefulfill, johnsonese, unforegone, unwrathful, dunderhead, erceldoune, unwadeable, refunction, understuff, swaggering, freckliest, telemachus, groundsill, outslidden, bolsheviks, recognizer, hemangioma, tarantella, muhammedan, talebearer, relocation, preemption, chachalaca, septuagint, ubiquitous, plexiglass, humoresque, biliverdin, tetraploid, capitoline, summerwood, undilating, undetested, meningitic, petrolatum, phytotoxic, adiphenine, flashlight, protectory, inwreathed, rawishness, tendrillar, hastefully, bananaquit, anarthrous, unbedimmed, herborized, decenniums, deprecated, karyotypic, squalidity, pomiferous, petroglyph, actinomere, peninsular, trigonally, androgenic, resistance, unassuming, frithstool, documental, eunuchised, interphone, thymbraeus, confirmand, expurgated, vegetation, myographic, plasmagene, spindrying, unlackeyed, foreknower, mythically, albescence, rebudgeted, implicitly, unmonastic, torricelli, mortarless, labialized, phenacaine, radiometry, sluggishly, understood, wiretapper, jacobitely, unbetrayed, stadholder, directress, emissaries, corelation, sensualize, uncurbable, permillage, tentacular, thriftless, demoralize, preimagine, iconoclast, acrobatism, firewarden, transpired, bluethroat, wanderjahr, groundable, pedestrian, unulcerous, preearthly, freelanced, sculleries, avengingly, visigothic, preharmony, bressummer, acceptable, unfoolable, predivider, overseeing, arcosolium, piriformis, needlecord, homebodies, sulphation, phantasmic, unsensible, unpackaged, isopiestic, cytophagic, butterlike, frizzliest, winklehawk, necrophile, mesothorax, cuchulainn, unrentable, untangible, unshifting, unfeasible, poetastric, extermined, gaillardia, nonpendent, harborside, pigsticker, infanthood, underrower, easterling, jockeyship, housebreak, horologium, undepicted, dysacousma, incurrable, editorship, unrelented, peritricha, interchaff, frothiness, underplant, proafrican, squareness, enigmatise, reconciled, nonnumeral, nonevident, hamantasch, victualing, watercolor, schrdinger, understand, butlerlike, hemiglobin, yankeeland";
|
||||
|
||||
@Test
|
||||
public void testMasiveUpdate(){
|
||||
|
||||
String randomDictionary = "spinneries, archipenko, prepotency, herniotomy, preexpress, relaxative, insolvably, debonnaire, apophysate, virtuality, cavalryman, utilizable, diagenesis, vitascopic, governessy, abranchial, cyanogenic, gratulated, signalment, predicable, subquality, crystalize, prosaicism, oenologist, repressive, impanelled, cockneyism, bordelaise, compigne, konstantin, predicated, unsublimed, hydrophane, phycomyces, capitalise, slippingly, untithable, unburnable, deoxidizer, misteacher, precorrect, disclaimer, solidified, neuraxitis, caravaning, betelgeuse, underprice, uninclosed, acrogynous, reirrigate, dazzlingly, chaffiness, corybantes, intumesced, intentness, superexert, abstrusely, astounding, pilgrimage, posttarsal, prayerless, nomologist, semibelted, frithstool, unstinging, ecalcarate, amputating, megascopic, graphalloy, platteland, adjacently, mingrelian, valentinus, appendical, unaccurate, coriaceous, waterworks, sympathize, doorkeeper, overguilty, flaggingly, admonitory, aeriferous, normocytic, parnellism, catafalque, odontiasis, apprentice, adulterous, mechanisma, wilderness, undivorced, reinterred, effleurage, pretrochal, phytogenic, swirlingly, herbarized, unresolved, classifier, diosmosing, microphage, consecrate, astarboard, predefying, predriving, lettergram, ungranular, overdozing, conferring, unfavorite, peacockish, coinciding, erythraeum, freeholder, zygophoric, imbitterer, centroidal, appendixes, grayfishes, enological, indiscreet, broadcloth, divulgated, anglophobe, stoopingly, bibliophil, laryngitis, separatist, estivating, bellarmine, greasiness, typhlology, xanthation, mortifying, endeavorer, aviatrices, unequalise, metastatic, leftwinger, apologizer, quatrefoil, nonfouling, bitartrate, outchiding, undeported, poussetted, haemolysis, asantehene, montgomery, unjoinable, cedarhurst, unfastener, nonvacuums, beauregard, animalized, polyphides, cannizzaro, gelatinoid, apologised, unscripted, tracheidal, subdiscoid, gravelling, variegated, interabang, inoperable, immortelle, laestrygon, duplicatus, proscience, deoxidised, manfulness, channelize, nondefense, ectomorphy, unimpelled, headwaiter, hexaemeric, derivation, prelexical, limitarian, nonionized, prorefugee, invariably, patronizer, paraplegia, redivision, occupative, unfaceable, hypomnesia, psalterium, doctorfish, gentlefolk, overrefine, heptastich, desirously, clarabelle, uneuphonic, autotelism, firewarden, timberjack, fumigation, drainpipes, spathulate, novelvelle, bicorporal, grisliness, unhesitant, supergiant, unpatented, womanpower, toastiness, multichord, paramnesia, undertrick, contrarily, neurogenic, gunmanship, settlement, brookville, gradualism, unossified, villanovan, ecospecies, organising, buckhannon, prefulfill, johnsonese, unforegone, unwrathful, dunderhead, erceldoune, unwadeable, refunction, understuff, swaggering, freckliest, telemachus, groundsill, outslidden, bolsheviks, recognizer, hemangioma, tarantella, muhammedan, talebearer, relocation, preemption, chachalaca, septuagint, ubiquitous, plexiglass, humoresque, biliverdin, tetraploid, capitoline, summerwood, undilating, undetested, meningitic, petrolatum, phytotoxic, adiphenine, flashlight, protectory, inwreathed, rawishness, tendrillar, hastefully, bananaquit, anarthrous, unbedimmed, herborized, decenniums, deprecated, karyotypic, squalidity, pomiferous, petroglyph, actinomere, peninsular, trigonally, androgenic, resistance, unassuming, frithstool, documental, eunuchised, interphone, thymbraeus, confirmand, expurgated, vegetation, myographic, plasmagene, spindrying, unlackeyed, foreknower, mythically, albescence, rebudgeted, implicitly, unmonastic, torricelli, mortarless, labialized, phenacaine, radiometry, sluggishly, understood, wiretapper, jacobitely, unbetrayed, stadholder, directress, emissaries, corelation, sensualize, uncurbable, permillage, tentacular, thriftless, demoralize, preimagine, iconoclast, acrobatism, firewarden, transpired, bluethroat, wanderjahr, groundable, pedestrian, unulcerous, preearthly, freelanced, sculleries, avengingly, visigothic, preharmony, bressummer, acceptable, unfoolable, predivider, overseeing, arcosolium, piriformis, needlecord, homebodies, sulphation, phantasmic, unsensible, unpackaged, isopiestic, cytophagic, butterlike, frizzliest, winklehawk, necrophile, mesothorax, cuchulainn, unrentable, untangible, unshifting, unfeasible, poetastric, extermined, gaillardia, nonpendent, harborside, pigsticker, infanthood, underrower, easterling, jockeyship, housebreak, horologium, undepicted, dysacousma, incurrable, editorship, unrelented, peritricha, interchaff, frothiness, underplant, proafrican, squareness, enigmatise, reconciled, nonnumeral, nonevident, hamantasch, victualing, watercolor, schrdinger, understand, butlerlike, hemiglobin, yankeeland";
|
||||
List<String> randomWords = Arrays.asList(randomDictionary.split(","));
|
||||
HashMap<String, String> testerMap = new HashMap<>();
|
||||
|
||||
Trie trie = new Trie(mockDb);
|
||||
Random generator = new Random();
|
||||
|
||||
// Random insertion
|
||||
for (int i = 0; i < 100000; ++i ){
|
||||
|
||||
int randomIndex1 = generator.nextInt(randomWords.size());
|
||||
int randomIndex2 = generator.nextInt(randomWords.size());
|
||||
|
||||
String word1 = randomWords.get(randomIndex1).trim();
|
||||
String word2 = randomWords.get(randomIndex2).trim();
|
||||
|
||||
trie.update(word1, word2);
|
||||
testerMap.put(word1, word2);
|
||||
}
|
||||
|
||||
int half = testerMap.size() / 2;
|
||||
for (int r = 0; r < half; ++r){
|
||||
|
||||
int randomIndex = generator.nextInt(randomWords.size());
|
||||
String word1 = randomWords.get(randomIndex).trim();
|
||||
|
||||
testerMap.remove(word1);
|
||||
trie.delete(word1);
|
||||
}
|
||||
|
||||
trie.cleanCacheGarbage();
|
||||
trie.sync();
|
||||
|
||||
// Assert the result now
|
||||
Iterator<String> keys = testerMap.keySet().iterator();
|
||||
while (keys.hasNext()){
|
||||
|
||||
String mapWord1 = keys.next();
|
||||
String mapWord2 = testerMap.get(mapWord1);
|
||||
String treeWord2 = new String(trie.get(mapWord1));
|
||||
|
||||
Assert.assertEquals(mapWord2, treeWord2);
|
||||
}
|
||||
boolean massiveUpdateTestEnabled = false;
|
||||
|
||||
if(massiveUpdateTestEnabled) {
|
||||
List<String> randomWords = Arrays.asList(randomDictionary.split(","));
|
||||
HashMap<String, String> testerMap = new HashMap<>();
|
||||
|
||||
Trie trie = new Trie(mockDb);
|
||||
Random generator = new Random();
|
||||
|
||||
// Random insertion
|
||||
for (int i = 0; i < 100000; ++i ){
|
||||
|
||||
int randomIndex1 = generator.nextInt(randomWords.size());
|
||||
int randomIndex2 = generator.nextInt(randomWords.size());
|
||||
|
||||
String word1 = randomWords.get(randomIndex1).trim();
|
||||
String word2 = randomWords.get(randomIndex2).trim();
|
||||
|
||||
trie.update(word1, word2);
|
||||
testerMap.put(word1, word2);
|
||||
}
|
||||
|
||||
int half = testerMap.size() / 2;
|
||||
for (int r = 0; r < half; ++r){
|
||||
|
||||
int randomIndex = generator.nextInt(randomWords.size());
|
||||
String word1 = randomWords.get(randomIndex).trim();
|
||||
|
||||
testerMap.remove(word1);
|
||||
trie.delete(word1);
|
||||
}
|
||||
|
||||
trie.cleanCacheGarbage();
|
||||
trie.sync();
|
||||
|
||||
// Assert the result now
|
||||
Iterator<String> keys = testerMap.keySet().iterator();
|
||||
while (keys.hasNext()){
|
||||
|
||||
String mapWord1 = keys.next();
|
||||
String mapWord2 = testerMap.get(mapWord1);
|
||||
String treeWord2 = new String(trie.get(mapWord1));
|
||||
|
||||
Assert.assertEquals(mapWord2, treeWord2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -636,56 +638,58 @@ public class TrieTest {
|
|||
assertEquals(trieSingle.getRootHash(), trie2.getRootHash());
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Test // tests saving keys to the file //
|
||||
public void testMasiveUpdateFromDB(){
|
||||
|
||||
String randomDictionary = "spinneries, archipenko, prepotency, herniotomy, preexpress, relaxative, insolvably, debonnaire, apophysate, virtuality, cavalryman, utilizable, diagenesis, vitascopic, governessy, abranchial, cyanogenic, gratulated, signalment, predicable, subquality, crystalize, prosaicism, oenologist, repressive, impanelled, cockneyism, bordelaise, compigne, konstantin, predicated, unsublimed, hydrophane, phycomyces, capitalise, slippingly, untithable, unburnable, deoxidizer, misteacher, precorrect, disclaimer, solidified, neuraxitis, caravaning, betelgeuse, underprice, uninclosed, acrogynous, reirrigate, dazzlingly, chaffiness, corybantes, intumesced, intentness, superexert, abstrusely, astounding, pilgrimage, posttarsal, prayerless, nomologist, semibelted, frithstool, unstinging, ecalcarate, amputating, megascopic, graphalloy, platteland, adjacently, mingrelian, valentinus, appendical, unaccurate, coriaceous, waterworks, sympathize, doorkeeper, overguilty, flaggingly, admonitory, aeriferous, normocytic, parnellism, catafalque, odontiasis, apprentice, adulterous, mechanisma, wilderness, undivorced, reinterred, effleurage, pretrochal, phytogenic, swirlingly, herbarized, unresolved, classifier, diosmosing, microphage, consecrate, astarboard, predefying, predriving, lettergram, ungranular, overdozing, conferring, unfavorite, peacockish, coinciding, erythraeum, freeholder, zygophoric, imbitterer, centroidal, appendixes, grayfishes, enological, indiscreet, broadcloth, divulgated, anglophobe, stoopingly, bibliophil, laryngitis, separatist, estivating, bellarmine, greasiness, typhlology, xanthation, mortifying, endeavorer, aviatrices, unequalise, metastatic, leftwinger, apologizer, quatrefoil, nonfouling, bitartrate, outchiding, undeported, poussetted, haemolysis, asantehene, montgomery, unjoinable, cedarhurst, unfastener, nonvacuums, beauregard, animalized, polyphides, cannizzaro, gelatinoid, apologised, unscripted, tracheidal, subdiscoid, gravelling, variegated, interabang, inoperable, immortelle, laestrygon, duplicatus, proscience, deoxidised, manfulness, channelize, nondefense, ectomorphy, unimpelled, headwaiter, hexaemeric, derivation, prelexical, limitarian, nonionized, prorefugee, invariably, patronizer, paraplegia, redivision, occupative, unfaceable, hypomnesia, psalterium, doctorfish, gentlefolk, overrefine, heptastich, desirously, clarabelle, uneuphonic, autotelism, firewarden, timberjack, fumigation, drainpipes, spathulate, novelvelle, bicorporal, grisliness, unhesitant, supergiant, unpatented, womanpower, toastiness, multichord, paramnesia, undertrick, contrarily, neurogenic, gunmanship, settlement, brookville, gradualism, unossified, villanovan, ecospecies, organising, buckhannon, prefulfill, johnsonese, unforegone, unwrathful, dunderhead, erceldoune, unwadeable, refunction, understuff, swaggering, freckliest, telemachus, groundsill, outslidden, bolsheviks, recognizer, hemangioma, tarantella, muhammedan, talebearer, relocation, preemption, chachalaca, septuagint, ubiquitous, plexiglass, humoresque, biliverdin, tetraploid, capitoline, summerwood, undilating, undetested, meningitic, petrolatum, phytotoxic, adiphenine, flashlight, protectory, inwreathed, rawishness, tendrillar, hastefully, bananaquit, anarthrous, unbedimmed, herborized, decenniums, deprecated, karyotypic, squalidity, pomiferous, petroglyph, actinomere, peninsular, trigonally, androgenic, resistance, unassuming, frithstool, documental, eunuchised, interphone, thymbraeus, confirmand, expurgated, vegetation, myographic, plasmagene, spindrying, unlackeyed, foreknower, mythically, albescence, rebudgeted, implicitly, unmonastic, torricelli, mortarless, labialized, phenacaine, radiometry, sluggishly, understood, wiretapper, jacobitely, unbetrayed, stadholder, directress, emissaries, corelation, sensualize, uncurbable, permillage, tentacular, thriftless, demoralize, preimagine, iconoclast, acrobatism, firewarden, transpired, bluethroat, wanderjahr, groundable, pedestrian, unulcerous, preearthly, freelanced, sculleries, avengingly, visigothic, preharmony, bressummer, acceptable, unfoolable, predivider, overseeing, arcosolium, piriformis, needlecord, homebodies, sulphation, phantasmic, unsensible, unpackaged, isopiestic, cytophagic, butterlike, frizzliest, winklehawk, necrophile, mesothorax, cuchulainn, unrentable, untangible, unshifting, unfeasible, poetastric, extermined, gaillardia, nonpendent, harborside, pigsticker, infanthood, underrower, easterling, jockeyship, housebreak, horologium, undepicted, dysacousma, incurrable, editorship, unrelented, peritricha, interchaff, frothiness, underplant, proafrican, squareness, enigmatise, reconciled, nonnumeral, nonevident, hamantasch, victualing, watercolor, schrdinger, understand, butlerlike, hemiglobin, yankeeland";
|
||||
List<String> randomWords = Arrays.asList(randomDictionary.split(","));
|
||||
HashMap<String, String> testerMap = new HashMap<>();
|
||||
|
||||
Trie trie = new Trie(mockDb);
|
||||
Random generator = new Random();
|
||||
|
||||
// Random insertion
|
||||
for (int i = 0; i < 50000; ++i ){
|
||||
|
||||
int randomIndex1 = generator.nextInt(randomWords.size());
|
||||
int randomIndex2 = generator.nextInt(randomWords.size());
|
||||
|
||||
String word1 = randomWords.get(randomIndex1).trim();
|
||||
String word2 = randomWords.get(randomIndex2).trim();
|
||||
|
||||
trie.update(word1, word2);
|
||||
testerMap.put(word1, word2);
|
||||
}
|
||||
|
||||
trie.cleanCacheGarbage();
|
||||
trie.sync();
|
||||
|
||||
// Assert the result now
|
||||
Iterator<String> keys = testerMap.keySet().iterator();
|
||||
while (keys.hasNext()){
|
||||
|
||||
String mapWord1 = keys.next();
|
||||
String mapWord2 = testerMap.get(mapWord1);
|
||||
String treeWord2 = new String(trie.get(mapWord1));
|
||||
|
||||
Assert.assertEquals(mapWord2, treeWord2);
|
||||
}
|
||||
|
||||
Trie trie2 = new Trie(mockDb, trie.getRootHash());
|
||||
|
||||
// Assert the result now
|
||||
keys = testerMap.keySet().iterator();
|
||||
while (keys.hasNext()){
|
||||
|
||||
String mapWord1 = keys.next();
|
||||
String mapWord2 = testerMap.get(mapWord1);
|
||||
String treeWord2 = new String(trie2.get(mapWord1));
|
||||
|
||||
Assert.assertEquals(mapWord2, treeWord2);
|
||||
}
|
||||
boolean massiveUpdateFromDBEnabled = false;
|
||||
|
||||
if(massiveUpdateFromDBEnabled) {
|
||||
List<String> randomWords = Arrays.asList(randomDictionary.split(","));
|
||||
HashMap<String, String> testerMap = new HashMap<>();
|
||||
|
||||
Trie trie = new Trie(mockDb);
|
||||
Random generator = new Random();
|
||||
|
||||
// Random insertion
|
||||
for (int i = 0; i < 50000; ++i ){
|
||||
|
||||
int randomIndex1 = generator.nextInt(randomWords.size());
|
||||
int randomIndex2 = generator.nextInt(randomWords.size());
|
||||
|
||||
String word1 = randomWords.get(randomIndex1).trim();
|
||||
String word2 = randomWords.get(randomIndex2).trim();
|
||||
|
||||
trie.update(word1, word2);
|
||||
testerMap.put(word1, word2);
|
||||
}
|
||||
|
||||
trie.cleanCacheGarbage();
|
||||
trie.sync();
|
||||
|
||||
// Assert the result now
|
||||
Iterator<String> keys = testerMap.keySet().iterator();
|
||||
while (keys.hasNext()){
|
||||
|
||||
String mapWord1 = keys.next();
|
||||
String mapWord2 = testerMap.get(mapWord1);
|
||||
String treeWord2 = new String(trie.get(mapWord1));
|
||||
|
||||
Assert.assertEquals(mapWord2, treeWord2);
|
||||
}
|
||||
|
||||
Trie trie2 = new Trie(mockDb, trie.getRootHash());
|
||||
|
||||
// Assert the result now
|
||||
keys = testerMap.keySet().iterator();
|
||||
while (keys.hasNext()){
|
||||
|
||||
String mapWord1 = keys.next();
|
||||
String mapWord2 = testerMap.get(mapWord1);
|
||||
String treeWord2 = new String(trie2.get(mapWord1));
|
||||
|
||||
Assert.assertEquals(mapWord2, treeWord2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -98,6 +98,20 @@ public class ByteUtilTest {
|
|||
assertEquals(0, result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNiceNiblesOutput_1(){
|
||||
byte[] test = {7, 0, 7, 5, 7, 0, 7, 0, 7, 9};
|
||||
String result = "\\x07\\x00\\x07\\x05\\x07\\x00\\x07\\x00\\x07\\x09";
|
||||
assertEquals(result, ByteUtil.nibblesToPrettyString(test));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNiceNiblesOutput_2(){
|
||||
byte[] test = {7, 0, 7, 0xf, 7, 0, 0xa, 0, 7, 9};
|
||||
String result = "\\x07\\x00\\x07\\x0f\\x07\\x00\\x0a\\x00\\x07\\x09";
|
||||
assertEquals(result, ByteUtil.nibblesToPrettyString(test));
|
||||
}
|
||||
|
||||
@Test(expected=NullPointerException.class)
|
||||
public void testMatchingNibbleLength5() {
|
||||
// a == null
|
||||
|
|
|
@ -85,22 +85,4 @@ public class CompactEncoderTest {
|
|||
byte[] result = new byte[] { 7, 0, 7, 5, 7, 0, 7, 0, 7, 9, T };
|
||||
assertArrayEquals(result, CompactEncoder.binToNibbles(test));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testNiceNiblesOutput_1(){
|
||||
byte[] test = {7, 0, 7, 5, 7, 0, 7, 0, 7, 9};
|
||||
String result = "\\x07\\x00\\x07\\x05\\x07\\x00\\x07\\x00\\x07\\x09";
|
||||
|
||||
assertEquals(result, CompactEncoder.nibblesToPrettyString(test));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNiceNiblesOutput_2(){
|
||||
byte[] test = {7, 0, 7, 0xf, 7, 0, 0xa, 0, 7, 9};
|
||||
String result = "\\x07\\x00\\x07\\x0f\\x07\\x00\\x0a\\x00\\x07\\x09";
|
||||
|
||||
assertEquals(result, CompactEncoder.nibblesToPrettyString(test));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue