Added missing files.

Some debugging changes.
This commit is contained in:
Adrian Tiberius 2015-05-26 22:48:43 +02:00
parent 43905b99a2
commit 92f2c29f69
27 changed files with 990 additions and 69 deletions

View File

@ -179,15 +179,15 @@ public class MainActivity extends ActionBarActivity implements OnClickListener,
Log.v(TAG, "333");
//ethereumManager.startPeerDiscovery();
while(true) {
/*
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
*/
if (quit == 1) {
return "All Done!";
//return "All Done!";
}
//publishProgress(1111);

View File

@ -104,7 +104,7 @@ dependencies {
//compile "com.octo.android.robospice:robospice-spring-android:1.4.14"
//compile 'com.octo.android.robospice:robospice-ormlite:1.4.14'
compile('io.netty:netty-all:4.0.26.Final') {
compile('io.netty:netty-all:4.1.0.Beta5') {
exclude group: 'commons-logging', module: 'commons-logging'
}
compile "com.madgag.spongycastle:core:${scastleVersion}"
@ -129,6 +129,7 @@ dependencies {
//compile 'org.javassist:javassist:3.15.0-GA'
compile 'org.slf4j:slf4j-android:1.7.12'
compile 'de.mindpipe.android:android-logging-log4j:1.0.3'
//compile "org.slf4j:slf4j-api:${slf4jVersion}"
//compile "log4j:log4j:${log4jVersion}"

View File

@ -0,0 +1,32 @@
package org.ethereum;
import org.ethereum.cli.CLIInterface;
import org.ethereum.config.SystemProperties;
import org.ethereum.facade.Ethereum;
import org.ethereum.facade.EthereumFactory;
import java.io.IOException;
import java.net.URISyntaxException;
import static org.ethereum.config.SystemProperties.CONFIG;
/**
* @author Roman Mandeleil
* @since 14.11.2014
*/
public class Start {
public static void main(String args[]) throws IOException, URISyntaxException {
CLIInterface.call(args);
Ethereum ethereum = EthereumFactory.createEthereum();
if (CONFIG.blocksLoader().equals(""))
ethereum.connect(
CONFIG.activePeerIP(),
CONFIG.activePeerPort(),
CONFIG.activePeerNodeid());
else
ethereum.getBlockLoader().loadBlocks();
}
}

View File

@ -18,7 +18,7 @@ public class SystemProperties {
private final static int DEFAULT_TX_APPROVE_TIMEOUT = 10;
private final static String DEFAULT_DISCOVERY_PEER_LIST = "poc-9.ethdev.com:30303";
private final static String DEFAULT_ACTIVE_PEER_NODEID = "bf01b54b6bc7faa203286dfb8359ce11d7b1fe822968fb4991f508d6f5a36ab7d9ae8af9b0d61c0467fb08567e0fb71cfb9925a370b69f9ede97927db473d1f5"; // FIXME
private final static String DEFAULT_ACTIVE_PEER_NODEID = ""; // FIXME
private final static String DEFAULT_ACTIVE_PEER_IP = "poc-9.ethdev.com";
private final static int DEFAULT_ACTIVE_PORT = 30303;
private final static String DEFAULT_SAMPLES_DIR = "samples";

View File

@ -250,11 +250,12 @@ public class BlockchainImpl implements Blockchain {
@Override
public void add(Block block) {
if (exitOn < block.getNumber()) {
if (exitOn < block.getNumber()){
System.out.print("Exiting after block.number: " + getBestBlock().getNumber());
System.exit(-1);
}
if(!isValid(block)){
logger.warn("Invalid block with number: {}", block.getNumber());
return;
@ -299,6 +300,7 @@ public class BlockchainImpl implements Blockchain {
track.commit();
repository.flush(); // saving to the disc
storeBlock(block, receipts);
// Remove all wallet transactions as they already approved by the net
@ -474,7 +476,6 @@ public class BlockchainImpl implements Blockchain {
}
}
return receipts;
}
@ -740,5 +741,4 @@ public class BlockchainImpl implements Blockchain {
public void setExitOn(long exitOn) {
this.exitOn = exitOn;
}
}
}

View File

@ -499,10 +499,11 @@ public class TransactionExecutor {
}
*/
/**
/**
* After any contract code finish the run the certain result should take place,
* according to the given circumstances.
*//*
private long applyProgramResult(ProgramResult result, BigInteger gasDebit,
BigInteger gasPrice, Repository repository, byte[] senderAddress,
byte[] contractAddress, byte[] coinbase, boolean initResults) {

View File

@ -84,9 +84,8 @@ public class Wallet {
this.accountProvider = accountProvider;
}
public void addNewAccount() {
Account account = accountProvider.get();
Account account = new Account(this.repository);
account.init();
String address = Hex.toHexString(account.getEcKey().getAddress());
rows.put(address, account);
@ -373,4 +372,4 @@ public class Wallet {
public void setHigh(long high) {
this.high = high;
}
}
}

View File

@ -0,0 +1,145 @@
package org.ethereum.datasource;
import org.ethereum.config.SystemProperties;
import org.iq80.leveldb.CompressionType;
import org.iq80.leveldb.DB;
import org.iq80.leveldb.DBIterator;
import org.iq80.leveldb.Options;
import org.iq80.leveldb.WriteBatch;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.io.IOException;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import static org.iq80.leveldb.impl.Iq80DBFactory.factory;
import android.content.Context;
/**
* @author Roman Mandeleil
* @since 18.01.2015
*/
public class AndroidLevelDbDataSource implements KeyValueDataSource {
private static final Logger logger = LoggerFactory.getLogger("db");
String name;
private DB db;
private Context context;
public AndroidLevelDbDataSource() {
}
public AndroidLevelDbDataSource(String name) {
this.name = name;
}
public void setContext(Context context) {
this.context = context;
}
@Override
public void init() {
if (name == null) throw new NullPointerException("no name set to the db");
Options options = new Options();
options.createIfMissing(true);
options.compressionType(CompressionType.NONE);
org.iq80.leveldb.Logger logger1 = new org.iq80.leveldb.Logger() {
public void log(String message) {
logger.debug(message);
}
};
options.logger(logger1);
try {
logger.debug("Opening database");
File dbLocation = context.getDir(SystemProperties.CONFIG.databaseDir(), 0);
File fileLocation = new File(dbLocation, name);
if (SystemProperties.CONFIG.databaseReset()) {
destroyDB(fileLocation);
}
logger.debug("Initializing new or existing database: '{}'", fileLocation.getAbsolutePath());
db = factory.open(fileLocation, options);
} catch (IOException ioe) {
logger.error(ioe.getMessage(), ioe);
throw new RuntimeException("Can't initialize database");
}
}
public void destroyDB(File fileLocation) {
logger.debug("Destroying existing database");
Options options = new Options();
try {
factory.destroy(fileLocation, options);
} catch (IOException e) {
logger.error(e.getMessage(), e);
}
}
@Override
public void setName(String name) {
this.name = name;
}
@Override
public byte[] get(byte[] key) {
return db.get(key);
}
@Override
public byte[] put(byte[] key, byte[] value) {
db.put(key, value);
return value;
}
@Override
public void delete(byte[] key) {
db.delete(key);
}
@Override
public Set<byte[]> keys() {
DBIterator dbIterator = db.iterator();
Set<byte[]> keys = new HashSet<>();
while (dbIterator.hasNext()) {
Map.Entry<byte[], byte[]> entry = dbIterator.next();
keys.add(entry.getKey());
}
return keys;
}
@Override
public void updateBatch(Map<byte[], byte[]> rows) {
WriteBatch batch = db.createWriteBatch();
for (Map.Entry<byte[], byte[]> row : rows.entrySet())
batch.put(row.getKey(), row.getValue());
db.write(batch);
}
@Override
public void close() {
try {
logger.info("Close db: {}", name);
db.close();
} catch (IOException e) {
logger.error("Failed to find the db file on the close: {} ", name);
}
}
}

View File

@ -19,7 +19,6 @@ import java.util.Map;
import java.util.Set;
import static org.iq80.leveldb.impl.Iq80DBFactory.factory;
import android.content.Context;
/**
* @author Roman Mandeleil
@ -31,7 +30,6 @@ public class LevelDbDataSource implements KeyValueDataSource {
String name;
private DB db;
private Context context;
public LevelDbDataSource() {
}
@ -40,10 +38,6 @@ public class LevelDbDataSource implements KeyValueDataSource {
this.name = name;
}
public void setContext(Context context) {
this.context = context;
}
@Override
public void init() {
@ -52,22 +46,17 @@ public class LevelDbDataSource implements KeyValueDataSource {
Options options = new Options();
options.createIfMissing(true);
options.compressionType(CompressionType.NONE);
org.iq80.leveldb.Logger logger1 = new org.iq80.leveldb.Logger() {
public void log(String message) {
logger.debug(message);
}
};
options.logger(logger1);
try {
logger.debug("Opening database");
File dbLocation = context.getDir(SystemProperties.CONFIG.databaseDir(), 0);
File dbLocation = new File(System.getProperty("user.dir") + "/" +
SystemProperties.CONFIG.databaseDir() + "/");
File fileLocation = new File(dbLocation, name);
if (SystemProperties.CONFIG.databaseReset()) {
destroyDB(fileLocation);
}
logger.debug("Initializing new or existing database: '{}'", fileLocation.getAbsolutePath());
logger.debug("Initializing new or existing database: '{}'", name);
db = factory.open(fileLocation, options);
} catch (IOException ioe) {
@ -142,4 +131,4 @@ public class LevelDbDataSource implements KeyValueDataSource {
logger.error("Failed to find the db file on the close: {} ", name);
}
}
}
}

View File

@ -2,8 +2,10 @@ package org.ethereum.di.modules;
import android.content.Context;
import org.ethereum.config.SystemProperties;
import org.ethereum.core.BlockchainImpl;
import org.ethereum.core.Wallet;
import org.ethereum.datasource.AndroidLevelDbDataSource;
import org.ethereum.datasource.KeyValueDataSource;
import org.ethereum.datasource.LevelDbDataSource;
import org.ethereum.db.BlockStore;
@ -58,8 +60,8 @@ public class EthereumModule {
@Provides
@Singleton
WorldManager provideWorldManager(Blockchain blockchain, Repository repository, Wallet wallet, PeerDiscovery peerDiscovery
,BlockStore blockStore, ChannelManager channelManager, EthereumListener listener) {
return new WorldManager(blockchain, repository, wallet, peerDiscovery, blockStore, channelManager, listener);
,BlockStore blockStore, ChannelManager channelManager, AdminInfo adminInfo, EthereumListener listener) {
return new WorldManager(blockchain, repository, wallet, peerDiscovery, blockStore, channelManager, adminInfo, listener);
}
@Provides
@ -79,9 +81,9 @@ public class EthereumModule {
@Provides
@Singleton
Repository provideRepository() {
LevelDbDataSource detailsDS = new LevelDbDataSource();
AndroidLevelDbDataSource detailsDS = new AndroidLevelDbDataSource();
detailsDS.setContext(context);
LevelDbDataSource stateDS = new LevelDbDataSource();
AndroidLevelDbDataSource stateDS = new AndroidLevelDbDataSource();
stateDS.setContext(context);
return new RepositoryImpl(detailsDS, stateDS);
}
@ -139,7 +141,7 @@ public class EthereumModule {
@Provides
MessageCodec provideMessageCodec(EthereumListener listener) {
return new MessageCodec(listener);
return new MessageCodec();
}
@Provides
@ -165,11 +167,11 @@ public class EthereumModule {
}
/*
@Provides
String provideRemoteId() {
return "bf01b54b6bc7faa203286dfb8359ce11d7b1fe822968fb4991f508d6f5a36ab7d9ae8af9b0d61c0467fb08567e0fb71cfb9925a370b69f9ede97927db473d1f5";
return SystemProperties.CONFIG.activePeerNodeid();
}
*/
}

View File

@ -19,7 +19,6 @@ import org.slf4j.LoggerFactory;
//import org.springframework.orm.hibernate4.LocalSessionFactoryBuilder;
//import org.springframework.transaction.annotation.EnableTransactionManagement;
import java.sql.SQLException;
import java.util.Collections;
import java.util.HashSet;
import java.util.Properties;
@ -88,9 +87,7 @@ public class CommonConfig {
Properties prop = new Properties();
if (SystemProperties.CONFIG.databaseReset())
prop.put("hibernate.hbm2ddl.auto", "create");
prop.put("hibernate.hbm2ddl.auto", "update");
prop.put("hibernate.format_sql", "true");
// todo: useful but annoying consider define by system.properties
@ -116,10 +113,9 @@ public class CommonConfig {
String url =
String.format("jdbc:hsqldb:file:./%s/blockchain/blockchain.db;" +
"create=%s;hsqldb.default_table_type=cached",
"create=true;hsqldb.default_table_type=cached",
SystemProperties.CONFIG.databaseDir(),
SystemProperties.CONFIG.databaseReset());
SystemProperties.CONFIG.databaseDir());
DriverManagerDataSource ds = new DriverManagerDataSource();
ds.setDriverClassName("org.hsqldb.jdbcDriver");
@ -127,9 +123,8 @@ public class CommonConfig {
ds.setUsername("sa");
return ds;
}
*/
}
}

View File

@ -29,6 +29,7 @@ import javax.inject.Provider;
import static org.ethereum.jsontestsuite.Utils.parseData;
import static org.ethereum.util.ByteUtil.EMPTY_BYTE_ARRAY;
import static org.ethereum.vm.VMUtils.saveProgramTraceFile;
/**
* @author Roman Mandeleil
@ -216,7 +217,7 @@ public class TestRunner {
e = ex;
}
String content = program.getProgramTrace().asJsonString(true);
//program.saveProgramTraceToFile(testCase.getName(), content);
saveProgramTraceFile(testCase.getName(), content);
if (testCase.getPost().size() == 0) {
if (vmDidThrowAnEception != true) {
@ -564,4 +565,4 @@ public class TestRunner {
public ProgramTrace getTrace() {
return trace;
}
}
}

View File

@ -15,7 +15,7 @@ import java.util.List;
public class AdminInfo {
private long startupTimeStamp = System.currentTimeMillis();;
private long startupTimeStamp;
private boolean consensus = true;
private List<Long> blockExecTime = new LinkedList<>();
@ -59,4 +59,4 @@ public class AdminInfo {
public List<Long> getBlockExecTime(){
return blockExecTime;
}
}
}

View File

@ -21,7 +21,7 @@ import static org.ethereum.config.SystemProperties.CONFIG;
//@Component
public class BlockLoader {
Blockchain blockchain;
private Blockchain blockchain;
Scanner scanner = null;
@ -65,4 +65,6 @@ public class BlockLoader {
}
}
}

View File

@ -59,14 +59,14 @@ public class WorldManager {
private ChannelManager channelManager;
// TODO: What is this doing here ?
private AdminInfo adminInfo;
private EthereumListener listener;
@Inject
public WorldManager(Blockchain blockchain, Repository repository, Wallet wallet, PeerDiscovery peerDiscovery
,BlockStore blockStore, ChannelManager channelManager, EthereumListener listener) {
,BlockStore blockStore, ChannelManager channelManager, AdminInfo adminInfo, EthereumListener listener) {
logger.info("World manager instantiated");
this.blockchain = blockchain;
this.repository = repository;
@ -74,6 +74,7 @@ public class WorldManager {
this.peerDiscovery = peerDiscovery;
this.blockStore = blockStore;
this.channelManager = channelManager;
this.adminInfo = adminInfo;
this.listener = listener;
this.init();
@ -215,4 +216,4 @@ public class WorldManager {
repository.close();
blockchain.close();
}
}
}

View File

@ -34,6 +34,7 @@ public enum ReasonCode {
*/
TOO_MANY_PEERS(0x04),
/**
* [0x05] Already have a running connection with this peer
*/

View File

@ -38,12 +38,12 @@ public class EthereumChannelInitializer extends ChannelInitializer<NioSocketChan
Provider<Channel> channelProvider;
@Inject
public EthereumChannelInitializer(Blockchain blockchain, ChannelManager channelManager, Provider<Channel> channelProvider) {
public EthereumChannelInitializer(Blockchain blockchain, ChannelManager channelManager, Provider<Channel> channelProvider, String remoteId) {
logger.info("Channel initializer instantiated");
this.blockchain = blockchain;
this.channelManager = channelManager;
this.channelProvider = channelProvider;
this.remoteId = "";
this.remoteId = remoteId;
}
@Override
@ -76,4 +76,4 @@ public class EthereumChannelInitializer extends ChannelInitializer<NioSocketChan
this.remoteId = remoteId;
}
}
}

View File

@ -61,8 +61,28 @@ public class MessageCodec extends ByteToMessageCodec<Message> {
public void channelActive(ChannelHandlerContext ctx) throws Exception {
initiate(ctx);
}
}
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
super.channelRead(ctx, msg);
}
@Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
super.channelReadComplete(ctx);
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
super.exceptionCaught(ctx, cause);
}
@Override
public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
super.userEventTriggered(ctx, evt);
}
}
/*
EthereumListener listener;
@Inject
@ -70,7 +90,7 @@ public class MessageCodec extends ByteToMessageCodec<Message> {
super();
this.listener = listener;
}
*/
@Override
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
if (!isHandshakeDone)
@ -99,7 +119,7 @@ public class MessageCodec extends ByteToMessageCodec<Message> {
if (loggerNet.isInfoEnabled())
loggerNet.info("From: \t{} \tRecv: \t{}", ctx.channel().remoteAddress(), msg);
listener.onRecvMessage(msg);
//listener.onRecvMessage(msg);
out.add(msg);
}
@ -108,7 +128,7 @@ public class MessageCodec extends ByteToMessageCodec<Message> {
protected void encode(ChannelHandlerContext ctx, Message msg, ByteBuf out) throws Exception {
String output = String.format("To: \t%s \tSend: \t%s", ctx.channel().remoteAddress(), msg);
listener.trace(output);
//listener.trace(output);
if (loggerNet.isInfoEnabled())
loggerNet.info("To: \t{} \tSend: \t{}", ctx.channel().remoteAddress(), msg);

View File

@ -0,0 +1,185 @@
package org.ethereum.vm;
import org.ethereum.vmtrace.ProgramTraceListener;
import java.util.LinkedList;
import java.util.List;
import static java.lang.Math.ceil;
import static java.lang.Math.min;
import static java.lang.String.format;
import static org.ethereum.util.ByteUtil.oneByteToHexString;
import static org.ethereum.util.ByteUtil.EMPTY_BYTE_ARRAY;
public class Memory implements ProgramTraceListenerAware {
private static final int CHUNK_SIZE = 1024;
private static final int WORD_SIZE = 32;
private List<byte[]> chunks = new LinkedList<>();
private int softSize;
private ProgramTraceListener traceListener;
@Override
public void setTraceListener(ProgramTraceListener traceListener) {
this.traceListener = traceListener;
}
public byte[] read(int address, int size) {
if (size <= 0) return EMPTY_BYTE_ARRAY;
extend(address, size);
byte[] data = new byte[size];
int chunkIndex = address / CHUNK_SIZE;
int chunkOffset = address % CHUNK_SIZE;
int toGrab = data.length;
int start = 0;
while (toGrab > 0) {
int copied = grabMax(chunkIndex, chunkOffset, toGrab, data, start);
// read next chunk from the start
++chunkIndex;
chunkOffset = 0;
// mark remind
toGrab -= copied;
start += copied;
}
return data;
}
public void write(int address, byte[] data) {
extend(address, data.length);
int chunkIndex = address / CHUNK_SIZE;
int chunkOffset = address % CHUNK_SIZE;
int toCapture = data.length;
int start = 0;
while (toCapture > 0) {
int captured = captureMax(chunkIndex, chunkOffset, toCapture, data, start);
// capture next chunk
++chunkIndex;
chunkOffset = 0;
// mark remind
toCapture -= captured;
start += captured;
}
if (traceListener != null) traceListener.onMemoryWrite(address, data);
}
public void extendAndWrite(int address, int allocSize, byte[] data) {
extend(address, allocSize);
write(address, data);
}
public void extend(int address, int size) {
if (size <= 0) return;
final int newSize = address + size;
int toAllocate = newSize - internalSize();
if (toAllocate > 0) {
addChunks((int) ceil((double) toAllocate / CHUNK_SIZE));
}
toAllocate = newSize - softSize;
if (toAllocate > 0) {
toAllocate = (int) ceil((double) toAllocate / WORD_SIZE) * WORD_SIZE;
softSize += toAllocate;
if (traceListener != null) traceListener.onMemoryExtend(toAllocate);
}
}
public DataWord readWord(int address) {
return new DataWord(read(address, 32));
}
// just access expecting all data valid
public byte readByte(int address) {
int chunkIndex = address / CHUNK_SIZE;
int chunkOffset = address % CHUNK_SIZE;
byte[] chunk = chunks.get(chunkIndex);
return chunk[chunkOffset];
}
@Override
public String toString() {
StringBuilder memoryData = new StringBuilder();
StringBuilder firstLine = new StringBuilder();
StringBuilder secondLine = new StringBuilder();
for (int i = 0; i < softSize; ++i) {
byte value = readByte(i);
// Check if value is ASCII
String character = ((byte) 0x20 <= value && value <= (byte) 0x7e) ? new String(new byte[]{value}) : "?";
firstLine.append(character).append("");
secondLine.append(oneByteToHexString(value)).append(" ");
if ((i + 1) % 8 == 0) {
String tmp = format("%4s", Integer.toString(i - 7, 16)).replace(" ", "0");
memoryData.append("").append(tmp).append(" ");
memoryData.append(firstLine).append(" ");
memoryData.append(secondLine);
if (i + 1 < softSize) memoryData.append("\n");
firstLine.setLength(0);
secondLine.setLength(0);
}
}
return memoryData.toString();
}
public int size() {
return softSize;
}
public int internalSize() {
return chunks.size() * CHUNK_SIZE;
}
public List<byte[]> getChunks() {
return new LinkedList<>(chunks);
}
private int captureMax(int chunkIndex, int chunkOffset, int size, byte[] src, int srcPos) {
byte[] chunk = chunks.get(chunkIndex);
int toCapture = min(size, chunk.length - chunkOffset);
System.arraycopy(src, srcPos, chunk, chunkOffset, toCapture);
return toCapture;
}
private int grabMax(int chunkIndex, int chunkOffset, int size, byte[] dest, int destPos) {
byte[] chunk = chunks.get(chunkIndex);
int toGrab = min(size, chunk.length - chunkOffset);
System.arraycopy(chunk, chunkOffset, dest, destPos, toGrab);
return toGrab;
}
private void addChunks(int num) {
for (int i = 0; i < num; ++i) {
chunks.add(new byte[CHUNK_SIZE]);
}
}
}

View File

@ -84,7 +84,7 @@ public class Program {
precompile();
}
}
private <T extends ProgramTraceListenerAware> T setupTraceListener(T traceListenerAware) {
traceListenerAware.setTraceListener(traceListener);
return traceListenerAware;
@ -350,7 +350,6 @@ public class Program {
newBalance, null, track, this.invokeData.getBlockStore(), invokeData.byTestingSuite());
ProgramResult result = new ProgramResult();
if (programCode.length != 0) {
VM vm = new VM();
Program program = new Program(programCode, programInvoke);
@ -409,6 +408,7 @@ public class Program {
/**
* That method is for internal code invocations
*
* - Normal calls invoke a specified contract which updates itself
* - Stateless calls invoke code from another contract, within the context of the caller
*
@ -799,7 +799,6 @@ public class Program {
}
}
public static String stringify(byte[] code, int index, String result) {
if (code == null || code.length == 0)
return result;
@ -1017,4 +1016,4 @@ public class Program {
}
}
}

View File

@ -0,0 +1,8 @@
package org.ethereum.vm;
import org.ethereum.vmtrace.ProgramTraceListener;
public interface ProgramTraceListenerAware {
void setTraceListener(ProgramTraceListener listener);
}

View File

@ -0,0 +1,37 @@
package org.ethereum.vm;
import org.ethereum.vmtrace.ProgramTraceListener;
public class Stack extends java.util.Stack<DataWord> implements ProgramTraceListenerAware {
private ProgramTraceListener traceListener;
@Override
public void setTraceListener(ProgramTraceListener listener) {
this.traceListener = listener;
}
@Override
public synchronized DataWord pop() {
if (traceListener != null) traceListener.onStackPop();
return super.pop();
}
@Override
public DataWord push(DataWord item) {
if (traceListener != null) traceListener.onStackPush(item);
return super.push(item);
}
public void swap(int from, int to) {
if (isAccessible(from) && isAccessible(to) && (from != to)) {
if (traceListener != null) traceListener.onStackSwap(from, to);
DataWord tmp = get(from);
set(from, set(to, tmp));
}
}
private boolean isAccessible(int from) {
return from >= 0 && from < size();
}
}

View File

@ -0,0 +1,178 @@
package org.ethereum.vm;
import org.ethereum.core.AccountState;
import org.ethereum.core.Block;
import org.ethereum.db.ByteArrayWrapper;
import org.ethereum.db.ContractDetails;
import org.ethereum.facade.Repository;
import org.ethereum.vmtrace.ProgramTraceListener;
import java.math.BigInteger;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
public class Storage implements Repository, ProgramTraceListenerAware {
private final Repository repository;
private final DataWord address;
private ProgramTraceListener traceListener;
public Storage(DataWord address, Repository repository) {
this.address = address;
this.repository = repository;
}
@Override
public void setTraceListener(ProgramTraceListener listener) {
this.traceListener = listener;
}
@Override
public AccountState createAccount(byte[] addr) {
return repository.createAccount(addr);
}
@Override
public boolean isExist(byte[] addr) {
return repository.isExist(addr);
}
@Override
public AccountState getAccountState(byte[] addr) {
return repository.getAccountState(addr);
}
@Override
public void delete(byte[] addr) {
if (canListenTrace(addr)) traceListener.onStorageClear();
repository.delete(addr);
}
@Override
public BigInteger increaseNonce(byte[] addr) {
return repository.increaseNonce(addr);
}
@Override
public BigInteger getNonce(byte[] addr) {
return repository.getNonce(addr);
}
@Override
public ContractDetails getContractDetails(byte[] addr) {
return repository.getContractDetails(addr);
}
@Override
public void saveCode(byte[] addr, byte[] code) {
repository.saveCode(addr, code);
}
@Override
public byte[] getCode(byte[] addr) {
return repository.getCode(addr);
}
@Override
public void addStorageRow(byte[] addr, DataWord key, DataWord value) {
if (canListenTrace(addr)) traceListener.onStoragePut(key, value);
repository.addStorageRow(addr, key, value);
}
private boolean canListenTrace(byte[] address) {
return this.address.equals(new DataWord(address)) && (traceListener != null);
}
@Override
public DataWord getStorageValue(byte[] addr, DataWord key) {
return repository.getStorageValue(addr, key);
}
@Override
public BigInteger getBalance(byte[] addr) {
return repository.getBalance(addr);
}
@Override
public BigInteger addBalance(byte[] addr, BigInteger value) {
return repository.addBalance(addr, value);
}
@Override
public Set<byte[]> getAccountsKeys() {
return repository.getAccountsKeys();
}
@Override
public void dumpState(Block block, long gasUsed, int txNumber, byte[] txHash) {
repository.dumpState(block, gasUsed, txNumber, txHash);
}
@Override
public Repository startTracking() {
return repository.startTracking();
}
@Override
public void flush() {
repository.flush();
}
@Override
public void commit() {
repository.commit();
}
@Override
public void rollback() {
repository.rollback();
}
@Override
public void syncToRoot(byte[] root) {
repository.syncToRoot(root);
}
@Override
public boolean isClosed() {
return repository.isClosed();
}
@Override
public void close() {
repository.close();
}
@Override
public void reset() {
repository.reset();
}
@Override
public void updateBatch(HashMap<ByteArrayWrapper, AccountState> accountStates, HashMap<ByteArrayWrapper, ContractDetails> contractDetails) {
for (ByteArrayWrapper address : contractDetails.keySet()) {
if (!canListenTrace(address.getData())) return;
ContractDetails details = contractDetails.get(address);
if (details.isDeleted()) {
traceListener.onStorageClear();
} else if (details.isDirty()) {
for (Map.Entry<DataWord, DataWord> entry : details.getStorage().entrySet()) {
traceListener.onStoragePut(entry.getKey(), entry.getValue());
}
}
}
repository.updateBatch(accountStates, contractDetails);
}
@Override
public byte[] getRoot() {
return repository.getRoot();
}
@Override
public void loadAccount(byte[] addr, HashMap<ByteArrayWrapper, AccountState> cacheAccounts, HashMap<ByteArrayWrapper, ContractDetails> cacheDetails) {
repository.loadAccount(addr, cacheAccounts, cacheDetails);
}
}

View File

@ -0,0 +1,138 @@
package org.ethereum.vm;
import org.ethereum.config.SystemProperties;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.*;
import java.util.zip.Deflater;
import java.util.zip.DeflaterOutputStream;
import java.util.zip.Inflater;
import java.util.zip.InflaterOutputStream;
import static java.lang.String.format;
import static java.lang.System.getProperty;
//import static java.util.Base64.getDecoder;
//import static java.util.Base64.getEncoder;
//import static org.springframework.util.StringUtils.isEmpty;
import static android.util.Base64.*;
public final class VMUtils {
private static final Logger LOGGER = LoggerFactory.getLogger("VM");
private static final SystemProperties CONFIG = new SystemProperties();
private VMUtils() {
}
public static void closeQuietly(Closeable closeable) {
try {
if (closeable != null) {
closeable.close();
}
} catch (IOException ioe) {
// ignore
}
}
private static File createProgramTraceFile(String txHash) {
File result = null;
if (CONFIG.vmTrace() && !CONFIG.vmTraceDir().isEmpty()) {
String pathname = format("%s/%s/%s/%s.json", getProperty("user.dir"), CONFIG.databaseDir(), CONFIG.vmTraceDir(), txHash);
File file = new File(pathname);
if (file.exists()) {
if (file.isFile() && file.canWrite()) {
result = file;
}
} else {
try {
file.getParentFile().mkdirs();
file.createNewFile();
result = file;
} catch (IOException e) {
// ignored
}
}
}
return result;
}
private static void writeStringToFile(File file, String data) {
OutputStream out = null;
try {
out = new FileOutputStream(file);
if (data != null) {
out.write(data.getBytes("UTF-8"));
}
} catch (Exception e){
LOGGER.error(format("Cannot write to file '%s': ", file.getAbsolutePath()), e);
} finally {
closeQuietly(out);
}
}
public static void saveProgramTraceFile(String txHash, String content) {
File file = createProgramTraceFile(txHash);
if (file != null) {
writeStringToFile(file, content);
}
}
private static final int BUF_SIZE = 4096;
private static void write(InputStream in, OutputStream out, int bufSize) throws IOException {
try {
byte[] buf = new byte[bufSize];
for (int count = in.read(buf); count != -1; count = in.read(buf)) {
out.write(buf, 0, count);
}
} finally {
closeQuietly(in);
closeQuietly(out);
}
}
private static byte[] compress(String content) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ByteArrayInputStream in = new ByteArrayInputStream(content.getBytes("UTF-8"));
DeflaterOutputStream out = new DeflaterOutputStream(baos, new Deflater(), BUF_SIZE);
write(in, out, BUF_SIZE);
return baos.toByteArray();
}
private static String decompress(byte[] data) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream(data.length);
ByteArrayInputStream in = new ByteArrayInputStream(data);
InflaterOutputStream out = new InflaterOutputStream(baos, new Inflater(), BUF_SIZE);
write(in, out, BUF_SIZE);
return new String(baos.toByteArray(), "UTF-8");
}
public static String zipAndEncode(String content) {
try {
return encodeToString(compress(content), DEFAULT);//getEncoder().encodeToString(compress(content));
} catch (Exception e) {
LOGGER.error("Cannot zip or encode: ", e);
return content;
}
}
public static String unzipAndDecode(String content) {
try {
return decompress(decode(content, DEFAULT));//decompress(getDecoder().decode(content));
} catch (Exception e) {
LOGGER.error("Cannot unzip or decode: ", e);
return content;
}
}
}

View File

@ -0,0 +1,136 @@
package org.ethereum.vmtrace;
import com.fasterxml.jackson.annotation.JsonInclude;
import org.ethereum.vm.DataWord;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static org.ethereum.util.ByteUtil.toHexString;
public class OpActions {
@JsonInclude(JsonInclude.Include.NON_NULL)
public static class Action {
public enum Name {
pop,
push,
swap,
extend,
write,
put,
remove,
clear;
}
private Name name;
private Map<String, Object> params;
public Name getName() {
return name;
}
public void setName(Name name) {
this.name = name;
}
public Map<String, Object> getParams() {
return params;
}
public void setParams(Map<String, Object> params) {
this.params = params;
}
Action addParam(String name, Object value) {
if (value != null) {
if (params == null) {
params = new HashMap<>();
}
params.put(name, value.toString());
}
return this;
}
}
private List<Action> stack = new ArrayList<>();
private List<Action> memory = new ArrayList<>();
private List<Action> storage = new ArrayList<>();
public List<Action> getStack() {
return stack;
}
public void setStack(List<Action> stack) {
this.stack = stack;
}
public List<Action> getMemory() {
return memory;
}
public void setMemory(List<Action> memory) {
this.memory = memory;
}
public List<Action> getStorage() {
return storage;
}
public void setStorage(List<Action> storage) {
this.storage = storage;
}
private static Action addAction(List<Action> container, Action.Name name) {
Action action = new Action();
action.setName(name);
container.add(action);
return action;
}
public Action addStackPop() {
return addAction(stack, Action.Name.pop);
}
public Action addStackPush(DataWord value) {
return addAction(stack, Action.Name.push)
.addParam("value", value);
}
public Action addStackSwap(int from, int to) {
return addAction(stack, Action.Name.swap)
.addParam("from", from)
.addParam("to", to);
}
public Action addMemoryExtend(long delta) {
return addAction(memory, Action.Name.extend)
.addParam("delta", delta);
}
public Action addMemoryWrite(int address, byte[] data) {
return addAction(memory, Action.Name.write)
.addParam("address", address)
.addParam("data", toHexString(data));
}
public Action addStoragePut(DataWord key, DataWord value) {
return addAction(storage, Action.Name.put)
.addParam("key", key)
.addParam("value", value);
}
public Action addStorageRemove(DataWord key) {
return addAction(storage, Action.Name.remove)
.addParam("key", key);
}
public Action addStorageClear() {
return addAction(storage, Action.Name.clear);
}
}

View File

@ -0,0 +1,51 @@
package org.ethereum.vmtrace;
import org.ethereum.vm.DataWord;
import static org.ethereum.config.SystemProperties.CONFIG;
public class ProgramTraceListener {
private final boolean enabled = CONFIG.vmTrace();
private OpActions actions = new OpActions();
public void onMemoryExtend(int delta) {
if (enabled) actions.addMemoryExtend(delta);
}
public void onMemoryWrite(int address, byte[] data) {
if (enabled) actions.addMemoryWrite(address, data);
}
public void onStackPop() {
if (enabled) actions.addStackPop();
}
public void onStackPush(DataWord value) {
if (enabled) actions.addStackPush(value);
}
public void onStackSwap(int from, int to) {
if (enabled) actions.addStackSwap(from, to);
}
public void onStoragePut(DataWord key, DataWord value) {
if (enabled) {
if (value.equals(DataWord.ZERO)) {
actions.addStorageRemove(key);
} else {
actions.addStoragePut(key, value);
}
}
}
public void onStorageClear() {
actions.addStorageClear();
}
public OpActions resetActions() {
OpActions actions = this.actions;
this.actions = new OpActions();
return actions;
}
}

View File

@ -2,7 +2,7 @@
# the search of the online peers
# values: [ip:port, ip:port, ip:port ...]
peer.discovery.ip.list = poc-7.ethdev.com:30303,\
185.43.109.23:30303
185.43.109.23:30303
@ -16,7 +16,6 @@ peer.active.ip = 162.243.46.9
peer.active.port = 30303
peer.active.nodeid = e437a4836b77ad9d9ffe73ee782ef2614e6d8370fcf62191a6e488276e23717147073a7ce0b444d485fff5a0c34c4577251a7a990cf80d8542e21b95aa8c5e6c
# heiko peer
#peer.active.ip = 188.106.121.253
#peer.active.port = 30303
@ -45,7 +44,7 @@ peer.active.nodeid = e437a4836b77ad9d9ffe73ee782ef2614e6d8370fcf62191a6e488276e2
# Peer for server to listen for incoming
# connections
peer.listen.port = 30303
peer.listen.port = 10101
#peer.listen.port = 40304
# specify if the mechanism
@ -127,6 +126,7 @@ vm.structured.trace = true
vm.structured.dir = vmtrace
vm.structured.compressed = true
# make changes to tracing options
# starting from certain block
# -1 don't make any tracing changes
@ -197,4 +197,4 @@ record.blocks=false
# from a rlp lines
# file and not for
# the net
blocks.loader=
blocks.loader=