parent
43905b99a2
commit
92f2c29f69
|
@ -179,15 +179,15 @@ public class MainActivity extends ActionBarActivity implements OnClickListener,
|
||||||
Log.v(TAG, "333");
|
Log.v(TAG, "333");
|
||||||
//ethereumManager.startPeerDiscovery();
|
//ethereumManager.startPeerDiscovery();
|
||||||
while(true) {
|
while(true) {
|
||||||
/*
|
|
||||||
try {
|
try {
|
||||||
Thread.sleep(50);
|
Thread.sleep(50);
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
if (quit == 1) {
|
if (quit == 1) {
|
||||||
return "All Done!";
|
//return "All Done!";
|
||||||
}
|
}
|
||||||
|
|
||||||
//publishProgress(1111);
|
//publishProgress(1111);
|
||||||
|
|
|
@ -104,7 +104,7 @@ dependencies {
|
||||||
//compile "com.octo.android.robospice:robospice-spring-android:1.4.14"
|
//compile "com.octo.android.robospice:robospice-spring-android:1.4.14"
|
||||||
|
|
||||||
//compile 'com.octo.android.robospice:robospice-ormlite: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'
|
exclude group: 'commons-logging', module: 'commons-logging'
|
||||||
}
|
}
|
||||||
compile "com.madgag.spongycastle:core:${scastleVersion}"
|
compile "com.madgag.spongycastle:core:${scastleVersion}"
|
||||||
|
@ -129,6 +129,7 @@ dependencies {
|
||||||
|
|
||||||
//compile 'org.javassist:javassist:3.15.0-GA'
|
//compile 'org.javassist:javassist:3.15.0-GA'
|
||||||
compile 'org.slf4j:slf4j-android:1.7.12'
|
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 "org.slf4j:slf4j-api:${slf4jVersion}"
|
||||||
|
|
||||||
//compile "log4j:log4j:${log4jVersion}"
|
//compile "log4j:log4j:${log4jVersion}"
|
||||||
|
|
|
@ -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();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -18,7 +18,7 @@ public class SystemProperties {
|
||||||
|
|
||||||
private final static int DEFAULT_TX_APPROVE_TIMEOUT = 10;
|
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_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 String DEFAULT_ACTIVE_PEER_IP = "poc-9.ethdev.com";
|
||||||
private final static int DEFAULT_ACTIVE_PORT = 30303;
|
private final static int DEFAULT_ACTIVE_PORT = 30303;
|
||||||
private final static String DEFAULT_SAMPLES_DIR = "samples";
|
private final static String DEFAULT_SAMPLES_DIR = "samples";
|
||||||
|
|
|
@ -250,11 +250,12 @@ public class BlockchainImpl implements Blockchain {
|
||||||
@Override
|
@Override
|
||||||
public void add(Block block) {
|
public void add(Block block) {
|
||||||
|
|
||||||
if (exitOn < block.getNumber()) {
|
if (exitOn < block.getNumber()){
|
||||||
System.out.print("Exiting after block.number: " + getBestBlock().getNumber());
|
System.out.print("Exiting after block.number: " + getBestBlock().getNumber());
|
||||||
System.exit(-1);
|
System.exit(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if(!isValid(block)){
|
if(!isValid(block)){
|
||||||
logger.warn("Invalid block with number: {}", block.getNumber());
|
logger.warn("Invalid block with number: {}", block.getNumber());
|
||||||
return;
|
return;
|
||||||
|
@ -299,6 +300,7 @@ public class BlockchainImpl implements Blockchain {
|
||||||
track.commit();
|
track.commit();
|
||||||
repository.flush(); // saving to the disc
|
repository.flush(); // saving to the disc
|
||||||
|
|
||||||
|
|
||||||
storeBlock(block, receipts);
|
storeBlock(block, receipts);
|
||||||
|
|
||||||
// Remove all wallet transactions as they already approved by the net
|
// Remove all wallet transactions as they already approved by the net
|
||||||
|
@ -474,7 +476,6 @@ public class BlockchainImpl implements Blockchain {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return receipts;
|
return receipts;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -740,5 +741,4 @@ public class BlockchainImpl implements Blockchain {
|
||||||
public void setExitOn(long exitOn) {
|
public void setExitOn(long exitOn) {
|
||||||
this.exitOn = exitOn;
|
this.exitOn = exitOn;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
|
||||||
|
|
|
@ -499,10 +499,11 @@ public class TransactionExecutor {
|
||||||
}
|
}
|
||||||
|
|
||||||
*/
|
*/
|
||||||
/**
|
/**
|
||||||
* After any contract code finish the run the certain result should take place,
|
* After any contract code finish the run the certain result should take place,
|
||||||
* according to the given circumstances.
|
* according to the given circumstances.
|
||||||
*//*
|
*//*
|
||||||
|
|
||||||
private long applyProgramResult(ProgramResult result, BigInteger gasDebit,
|
private long applyProgramResult(ProgramResult result, BigInteger gasDebit,
|
||||||
BigInteger gasPrice, Repository repository, byte[] senderAddress,
|
BigInteger gasPrice, Repository repository, byte[] senderAddress,
|
||||||
byte[] contractAddress, byte[] coinbase, boolean initResults) {
|
byte[] contractAddress, byte[] coinbase, boolean initResults) {
|
||||||
|
|
|
@ -84,9 +84,8 @@ public class Wallet {
|
||||||
this.accountProvider = accountProvider;
|
this.accountProvider = accountProvider;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void addNewAccount() {
|
public void addNewAccount() {
|
||||||
Account account = accountProvider.get();
|
Account account = new Account(this.repository);
|
||||||
account.init();
|
account.init();
|
||||||
String address = Hex.toHexString(account.getEcKey().getAddress());
|
String address = Hex.toHexString(account.getEcKey().getAddress());
|
||||||
rows.put(address, account);
|
rows.put(address, account);
|
||||||
|
@ -373,4 +372,4 @@ public class Wallet {
|
||||||
public void setHigh(long high) {
|
public void setHigh(long high) {
|
||||||
this.high = high;
|
this.high = high;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -19,7 +19,6 @@ import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import static org.iq80.leveldb.impl.Iq80DBFactory.factory;
|
import static org.iq80.leveldb.impl.Iq80DBFactory.factory;
|
||||||
import android.content.Context;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Roman Mandeleil
|
* @author Roman Mandeleil
|
||||||
|
@ -31,7 +30,6 @@ public class LevelDbDataSource implements KeyValueDataSource {
|
||||||
|
|
||||||
String name;
|
String name;
|
||||||
private DB db;
|
private DB db;
|
||||||
private Context context;
|
|
||||||
|
|
||||||
public LevelDbDataSource() {
|
public LevelDbDataSource() {
|
||||||
}
|
}
|
||||||
|
@ -40,10 +38,6 @@ public class LevelDbDataSource implements KeyValueDataSource {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setContext(Context context) {
|
|
||||||
this.context = context;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void init() {
|
public void init() {
|
||||||
|
|
||||||
|
@ -52,22 +46,17 @@ public class LevelDbDataSource implements KeyValueDataSource {
|
||||||
Options options = new Options();
|
Options options = new Options();
|
||||||
options.createIfMissing(true);
|
options.createIfMissing(true);
|
||||||
options.compressionType(CompressionType.NONE);
|
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 {
|
try {
|
||||||
logger.debug("Opening database");
|
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);
|
File fileLocation = new File(dbLocation, name);
|
||||||
|
|
||||||
if (SystemProperties.CONFIG.databaseReset()) {
|
if (SystemProperties.CONFIG.databaseReset()) {
|
||||||
destroyDB(fileLocation);
|
destroyDB(fileLocation);
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.debug("Initializing new or existing database: '{}'", fileLocation.getAbsolutePath());
|
logger.debug("Initializing new or existing database: '{}'", name);
|
||||||
db = factory.open(fileLocation, options);
|
db = factory.open(fileLocation, options);
|
||||||
|
|
||||||
} catch (IOException ioe) {
|
} catch (IOException ioe) {
|
||||||
|
@ -142,4 +131,4 @@ public class LevelDbDataSource implements KeyValueDataSource {
|
||||||
logger.error("Failed to find the db file on the close: {} ", name);
|
logger.error("Failed to find the db file on the close: {} ", name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,8 +2,10 @@ package org.ethereum.di.modules;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
|
||||||
|
import org.ethereum.config.SystemProperties;
|
||||||
import org.ethereum.core.BlockchainImpl;
|
import org.ethereum.core.BlockchainImpl;
|
||||||
import org.ethereum.core.Wallet;
|
import org.ethereum.core.Wallet;
|
||||||
|
import org.ethereum.datasource.AndroidLevelDbDataSource;
|
||||||
import org.ethereum.datasource.KeyValueDataSource;
|
import org.ethereum.datasource.KeyValueDataSource;
|
||||||
import org.ethereum.datasource.LevelDbDataSource;
|
import org.ethereum.datasource.LevelDbDataSource;
|
||||||
import org.ethereum.db.BlockStore;
|
import org.ethereum.db.BlockStore;
|
||||||
|
@ -58,8 +60,8 @@ public class EthereumModule {
|
||||||
@Provides
|
@Provides
|
||||||
@Singleton
|
@Singleton
|
||||||
WorldManager provideWorldManager(Blockchain blockchain, Repository repository, Wallet wallet, PeerDiscovery peerDiscovery
|
WorldManager provideWorldManager(Blockchain blockchain, Repository repository, Wallet wallet, PeerDiscovery peerDiscovery
|
||||||
,BlockStore blockStore, ChannelManager channelManager, EthereumListener listener) {
|
,BlockStore blockStore, ChannelManager channelManager, AdminInfo adminInfo, EthereumListener listener) {
|
||||||
return new WorldManager(blockchain, repository, wallet, peerDiscovery, blockStore, channelManager, listener);
|
return new WorldManager(blockchain, repository, wallet, peerDiscovery, blockStore, channelManager, adminInfo, listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
|
@ -79,9 +81,9 @@ public class EthereumModule {
|
||||||
@Provides
|
@Provides
|
||||||
@Singleton
|
@Singleton
|
||||||
Repository provideRepository() {
|
Repository provideRepository() {
|
||||||
LevelDbDataSource detailsDS = new LevelDbDataSource();
|
AndroidLevelDbDataSource detailsDS = new AndroidLevelDbDataSource();
|
||||||
detailsDS.setContext(context);
|
detailsDS.setContext(context);
|
||||||
LevelDbDataSource stateDS = new LevelDbDataSource();
|
AndroidLevelDbDataSource stateDS = new AndroidLevelDbDataSource();
|
||||||
stateDS.setContext(context);
|
stateDS.setContext(context);
|
||||||
return new RepositoryImpl(detailsDS, stateDS);
|
return new RepositoryImpl(detailsDS, stateDS);
|
||||||
}
|
}
|
||||||
|
@ -139,7 +141,7 @@ public class EthereumModule {
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
MessageCodec provideMessageCodec(EthereumListener listener) {
|
MessageCodec provideMessageCodec(EthereumListener listener) {
|
||||||
return new MessageCodec(listener);
|
return new MessageCodec();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
|
@ -165,11 +167,11 @@ public class EthereumModule {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
@Provides
|
@Provides
|
||||||
String provideRemoteId() {
|
String provideRemoteId() {
|
||||||
return "bf01b54b6bc7faa203286dfb8359ce11d7b1fe822968fb4991f508d6f5a36ab7d9ae8af9b0d61c0467fb08567e0fb71cfb9925a370b69f9ede97927db473d1f5";
|
return SystemProperties.CONFIG.activePeerNodeid();
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,7 +19,6 @@ import org.slf4j.LoggerFactory;
|
||||||
//import org.springframework.orm.hibernate4.LocalSessionFactoryBuilder;
|
//import org.springframework.orm.hibernate4.LocalSessionFactoryBuilder;
|
||||||
//import org.springframework.transaction.annotation.EnableTransactionManagement;
|
//import org.springframework.transaction.annotation.EnableTransactionManagement;
|
||||||
|
|
||||||
import java.sql.SQLException;
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
|
@ -88,9 +87,7 @@ public class CommonConfig {
|
||||||
|
|
||||||
Properties prop = new Properties();
|
Properties prop = new Properties();
|
||||||
|
|
||||||
if (SystemProperties.CONFIG.databaseReset())
|
prop.put("hibernate.hbm2ddl.auto", "update");
|
||||||
prop.put("hibernate.hbm2ddl.auto", "create");
|
|
||||||
|
|
||||||
prop.put("hibernate.format_sql", "true");
|
prop.put("hibernate.format_sql", "true");
|
||||||
|
|
||||||
// todo: useful but annoying consider define by system.properties
|
// todo: useful but annoying consider define by system.properties
|
||||||
|
@ -116,10 +113,9 @@ public class CommonConfig {
|
||||||
|
|
||||||
String url =
|
String url =
|
||||||
String.format("jdbc:hsqldb:file:./%s/blockchain/blockchain.db;" +
|
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.databaseDir());
|
||||||
SystemProperties.CONFIG.databaseReset());
|
|
||||||
|
|
||||||
DriverManagerDataSource ds = new DriverManagerDataSource();
|
DriverManagerDataSource ds = new DriverManagerDataSource();
|
||||||
ds.setDriverClassName("org.hsqldb.jdbcDriver");
|
ds.setDriverClassName("org.hsqldb.jdbcDriver");
|
||||||
|
@ -127,9 +123,8 @@ public class CommonConfig {
|
||||||
ds.setUsername("sa");
|
ds.setUsername("sa");
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return ds;
|
return ds;
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,6 +29,7 @@ import javax.inject.Provider;
|
||||||
|
|
||||||
import static org.ethereum.jsontestsuite.Utils.parseData;
|
import static org.ethereum.jsontestsuite.Utils.parseData;
|
||||||
import static org.ethereum.util.ByteUtil.EMPTY_BYTE_ARRAY;
|
import static org.ethereum.util.ByteUtil.EMPTY_BYTE_ARRAY;
|
||||||
|
import static org.ethereum.vm.VMUtils.saveProgramTraceFile;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Roman Mandeleil
|
* @author Roman Mandeleil
|
||||||
|
@ -216,7 +217,7 @@ public class TestRunner {
|
||||||
e = ex;
|
e = ex;
|
||||||
}
|
}
|
||||||
String content = program.getProgramTrace().asJsonString(true);
|
String content = program.getProgramTrace().asJsonString(true);
|
||||||
//program.saveProgramTraceToFile(testCase.getName(), content);
|
saveProgramTraceFile(testCase.getName(), content);
|
||||||
|
|
||||||
if (testCase.getPost().size() == 0) {
|
if (testCase.getPost().size() == 0) {
|
||||||
if (vmDidThrowAnEception != true) {
|
if (vmDidThrowAnEception != true) {
|
||||||
|
@ -564,4 +565,4 @@ public class TestRunner {
|
||||||
public ProgramTrace getTrace() {
|
public ProgramTrace getTrace() {
|
||||||
return trace;
|
return trace;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,7 @@ import java.util.List;
|
||||||
public class AdminInfo {
|
public class AdminInfo {
|
||||||
|
|
||||||
|
|
||||||
private long startupTimeStamp = System.currentTimeMillis();;
|
private long startupTimeStamp;
|
||||||
private boolean consensus = true;
|
private boolean consensus = true;
|
||||||
private List<Long> blockExecTime = new LinkedList<>();
|
private List<Long> blockExecTime = new LinkedList<>();
|
||||||
|
|
||||||
|
@ -59,4 +59,4 @@ public class AdminInfo {
|
||||||
public List<Long> getBlockExecTime(){
|
public List<Long> getBlockExecTime(){
|
||||||
return blockExecTime;
|
return blockExecTime;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,7 +21,7 @@ import static org.ethereum.config.SystemProperties.CONFIG;
|
||||||
//@Component
|
//@Component
|
||||||
public class BlockLoader {
|
public class BlockLoader {
|
||||||
|
|
||||||
Blockchain blockchain;
|
private Blockchain blockchain;
|
||||||
|
|
||||||
Scanner scanner = null;
|
Scanner scanner = null;
|
||||||
|
|
||||||
|
@ -65,4 +65,6 @@ public class BlockLoader {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -59,14 +59,14 @@ public class WorldManager {
|
||||||
|
|
||||||
private ChannelManager channelManager;
|
private ChannelManager channelManager;
|
||||||
|
|
||||||
// TODO: What is this doing here ?
|
|
||||||
private AdminInfo adminInfo;
|
private AdminInfo adminInfo;
|
||||||
|
|
||||||
|
|
||||||
private EthereumListener listener;
|
private EthereumListener listener;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public WorldManager(Blockchain blockchain, Repository repository, Wallet wallet, PeerDiscovery peerDiscovery
|
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");
|
logger.info("World manager instantiated");
|
||||||
this.blockchain = blockchain;
|
this.blockchain = blockchain;
|
||||||
this.repository = repository;
|
this.repository = repository;
|
||||||
|
@ -74,6 +74,7 @@ public class WorldManager {
|
||||||
this.peerDiscovery = peerDiscovery;
|
this.peerDiscovery = peerDiscovery;
|
||||||
this.blockStore = blockStore;
|
this.blockStore = blockStore;
|
||||||
this.channelManager = channelManager;
|
this.channelManager = channelManager;
|
||||||
|
this.adminInfo = adminInfo;
|
||||||
this.listener = listener;
|
this.listener = listener;
|
||||||
|
|
||||||
this.init();
|
this.init();
|
||||||
|
@ -215,4 +216,4 @@ public class WorldManager {
|
||||||
repository.close();
|
repository.close();
|
||||||
blockchain.close();
|
blockchain.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,6 +34,7 @@ public enum ReasonCode {
|
||||||
*/
|
*/
|
||||||
TOO_MANY_PEERS(0x04),
|
TOO_MANY_PEERS(0x04),
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* [0x05] Already have a running connection with this peer
|
* [0x05] Already have a running connection with this peer
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -38,12 +38,12 @@ public class EthereumChannelInitializer extends ChannelInitializer<NioSocketChan
|
||||||
Provider<Channel> channelProvider;
|
Provider<Channel> channelProvider;
|
||||||
|
|
||||||
@Inject
|
@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");
|
logger.info("Channel initializer instantiated");
|
||||||
this.blockchain = blockchain;
|
this.blockchain = blockchain;
|
||||||
this.channelManager = channelManager;
|
this.channelManager = channelManager;
|
||||||
this.channelProvider = channelProvider;
|
this.channelProvider = channelProvider;
|
||||||
this.remoteId = "";
|
this.remoteId = remoteId;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -76,4 +76,4 @@ public class EthereumChannelInitializer extends ChannelInitializer<NioSocketChan
|
||||||
this.remoteId = remoteId;
|
this.remoteId = remoteId;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -61,8 +61,28 @@ public class MessageCodec extends ByteToMessageCodec<Message> {
|
||||||
public void channelActive(ChannelHandlerContext ctx) throws Exception {
|
public void channelActive(ChannelHandlerContext ctx) throws Exception {
|
||||||
initiate(ctx);
|
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;
|
EthereumListener listener;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
|
@ -70,7 +90,7 @@ public class MessageCodec extends ByteToMessageCodec<Message> {
|
||||||
super();
|
super();
|
||||||
this.listener = listener;
|
this.listener = listener;
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
|
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
|
||||||
if (!isHandshakeDone)
|
if (!isHandshakeDone)
|
||||||
|
@ -99,7 +119,7 @@ public class MessageCodec extends ByteToMessageCodec<Message> {
|
||||||
if (loggerNet.isInfoEnabled())
|
if (loggerNet.isInfoEnabled())
|
||||||
loggerNet.info("From: \t{} \tRecv: \t{}", ctx.channel().remoteAddress(), msg);
|
loggerNet.info("From: \t{} \tRecv: \t{}", ctx.channel().remoteAddress(), msg);
|
||||||
|
|
||||||
listener.onRecvMessage(msg);
|
//listener.onRecvMessage(msg);
|
||||||
|
|
||||||
out.add(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 {
|
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);
|
String output = String.format("To: \t%s \tSend: \t%s", ctx.channel().remoteAddress(), msg);
|
||||||
listener.trace(output);
|
//listener.trace(output);
|
||||||
|
|
||||||
if (loggerNet.isInfoEnabled())
|
if (loggerNet.isInfoEnabled())
|
||||||
loggerNet.info("To: \t{} \tSend: \t{}", ctx.channel().remoteAddress(), msg);
|
loggerNet.info("To: \t{} \tSend: \t{}", ctx.channel().remoteAddress(), msg);
|
||||||
|
|
|
@ -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]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -84,7 +84,7 @@ public class Program {
|
||||||
precompile();
|
precompile();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private <T extends ProgramTraceListenerAware> T setupTraceListener(T traceListenerAware) {
|
private <T extends ProgramTraceListenerAware> T setupTraceListener(T traceListenerAware) {
|
||||||
traceListenerAware.setTraceListener(traceListener);
|
traceListenerAware.setTraceListener(traceListener);
|
||||||
return traceListenerAware;
|
return traceListenerAware;
|
||||||
|
@ -350,7 +350,6 @@ public class Program {
|
||||||
newBalance, null, track, this.invokeData.getBlockStore(), invokeData.byTestingSuite());
|
newBalance, null, track, this.invokeData.getBlockStore(), invokeData.byTestingSuite());
|
||||||
|
|
||||||
ProgramResult result = new ProgramResult();
|
ProgramResult result = new ProgramResult();
|
||||||
|
|
||||||
if (programCode.length != 0) {
|
if (programCode.length != 0) {
|
||||||
VM vm = new VM();
|
VM vm = new VM();
|
||||||
Program program = new Program(programCode, programInvoke);
|
Program program = new Program(programCode, programInvoke);
|
||||||
|
@ -409,6 +408,7 @@ public class Program {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* That method is for internal code invocations
|
* That method is for internal code invocations
|
||||||
|
*
|
||||||
* - Normal calls invoke a specified contract which updates itself
|
* - Normal calls invoke a specified contract which updates itself
|
||||||
* - Stateless calls invoke code from another contract, within the context of the caller
|
* - 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) {
|
public static String stringify(byte[] code, int index, String result) {
|
||||||
if (code == null || code.length == 0)
|
if (code == null || code.length == 0)
|
||||||
return result;
|
return result;
|
||||||
|
@ -1017,4 +1016,4 @@ public class Program {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
package org.ethereum.vm;
|
||||||
|
|
||||||
|
import org.ethereum.vmtrace.ProgramTraceListener;
|
||||||
|
|
||||||
|
public interface ProgramTraceListenerAware {
|
||||||
|
|
||||||
|
void setTraceListener(ProgramTraceListener listener);
|
||||||
|
}
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,7 +2,7 @@
|
||||||
# the search of the online peers
|
# the search of the online peers
|
||||||
# values: [ip:port, ip:port, ip:port ...]
|
# values: [ip:port, ip:port, ip:port ...]
|
||||||
peer.discovery.ip.list = poc-7.ethdev.com:30303,\
|
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.port = 30303
|
||||||
peer.active.nodeid = e437a4836b77ad9d9ffe73ee782ef2614e6d8370fcf62191a6e488276e23717147073a7ce0b444d485fff5a0c34c4577251a7a990cf80d8542e21b95aa8c5e6c
|
peer.active.nodeid = e437a4836b77ad9d9ffe73ee782ef2614e6d8370fcf62191a6e488276e23717147073a7ce0b444d485fff5a0c34c4577251a7a990cf80d8542e21b95aa8c5e6c
|
||||||
|
|
||||||
|
|
||||||
# heiko peer
|
# heiko peer
|
||||||
#peer.active.ip = 188.106.121.253
|
#peer.active.ip = 188.106.121.253
|
||||||
#peer.active.port = 30303
|
#peer.active.port = 30303
|
||||||
|
@ -45,7 +44,7 @@ peer.active.nodeid = e437a4836b77ad9d9ffe73ee782ef2614e6d8370fcf62191a6e488276e2
|
||||||
# Peer for server to listen for incoming
|
# Peer for server to listen for incoming
|
||||||
# connections
|
# connections
|
||||||
|
|
||||||
peer.listen.port = 30303
|
peer.listen.port = 10101
|
||||||
#peer.listen.port = 40304
|
#peer.listen.port = 40304
|
||||||
|
|
||||||
# specify if the mechanism
|
# specify if the mechanism
|
||||||
|
@ -127,6 +126,7 @@ vm.structured.trace = true
|
||||||
vm.structured.dir = vmtrace
|
vm.structured.dir = vmtrace
|
||||||
vm.structured.compressed = true
|
vm.structured.compressed = true
|
||||||
|
|
||||||
|
|
||||||
# make changes to tracing options
|
# make changes to tracing options
|
||||||
# starting from certain block
|
# starting from certain block
|
||||||
# -1 don't make any tracing changes
|
# -1 don't make any tracing changes
|
||||||
|
@ -197,4 +197,4 @@ record.blocks=false
|
||||||
# from a rlp lines
|
# from a rlp lines
|
||||||
# file and not for
|
# file and not for
|
||||||
# the net
|
# the net
|
||||||
blocks.loader=
|
blocks.loader=
|
Loading…
Reference in New Issue