From 92f2c29f699beb1f3b84ecbbd7be51320d9ed449 Mon Sep 17 00:00:00 2001 From: Adrian Tiberius Date: Tue, 26 May 2015 22:48:43 +0200 Subject: [PATCH] Added missing files. Some debugging changes. --- .../ethereum_android/MainActivity.java | 6 +- ethereumj-core/build.gradle | 3 +- .../src/main/java/org/ethereum/Start.java | 32 +++ .../org/ethereum/config/SystemProperties.java | 2 +- .../org/ethereum/core/BlockchainImpl.java | 8 +- .../ethereum/core/TransactionExecutor.java | 3 +- .../main/java/org/ethereum/core/Wallet.java | 5 +- .../datasource/AndroidLevelDbDataSource.java | 145 ++++++++++++++ .../datasource/LevelDbDataSource.java | 19 +- .../ethereum/di/modules/EthereumModule.java | 18 +- .../org/ethereum/facade/CommonConfig.java | 13 +- .../ethereum/jsontestsuite/TestRunner.java | 5 +- .../java/org/ethereum/manager/AdminInfo.java | 4 +- .../org/ethereum/manager/BlockLoader.java | 6 +- .../org/ethereum/manager/WorldManager.java | 7 +- .../org/ethereum/net/message/ReasonCode.java | 1 + .../server/EthereumChannelInitializer.java | 6 +- .../org/ethereum/net/wire/MessageCodec.java | 28 ++- .../src/main/java/org/ethereum/vm/Memory.java | 185 ++++++++++++++++++ .../main/java/org/ethereum/vm/Program.java | 7 +- .../vm/ProgramTraceListenerAware.java | 8 + .../src/main/java/org/ethereum/vm/Stack.java | 37 ++++ .../main/java/org/ethereum/vm/Storage.java | 178 +++++++++++++++++ .../main/java/org/ethereum/vm/VMUtils.java | 138 +++++++++++++ .../java/org/ethereum/vmtrace/OpActions.java | 136 +++++++++++++ .../vmtrace/ProgramTraceListener.java | 51 +++++ .../src/main/resources/system.properties | 8 +- 27 files changed, 990 insertions(+), 69 deletions(-) create mode 100644 ethereumj-core/src/main/java/org/ethereum/Start.java create mode 100644 ethereumj-core/src/main/java/org/ethereum/datasource/AndroidLevelDbDataSource.java create mode 100644 ethereumj-core/src/main/java/org/ethereum/vm/Memory.java create mode 100644 ethereumj-core/src/main/java/org/ethereum/vm/ProgramTraceListenerAware.java create mode 100644 ethereumj-core/src/main/java/org/ethereum/vm/Stack.java create mode 100644 ethereumj-core/src/main/java/org/ethereum/vm/Storage.java create mode 100644 ethereumj-core/src/main/java/org/ethereum/vm/VMUtils.java create mode 100644 ethereumj-core/src/main/java/org/ethereum/vmtrace/OpActions.java create mode 100644 ethereumj-core/src/main/java/org/ethereum/vmtrace/ProgramTraceListener.java diff --git a/app/src/main/java/org/ethereum/ethereum_android/MainActivity.java b/app/src/main/java/org/ethereum/ethereum_android/MainActivity.java index 3a8f2b72..44df2ac2 100644 --- a/app/src/main/java/org/ethereum/ethereum_android/MainActivity.java +++ b/app/src/main/java/org/ethereum/ethereum_android/MainActivity.java @@ -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); diff --git a/ethereumj-core/build.gradle b/ethereumj-core/build.gradle index 0e4e1841..d6935d59 100644 --- a/ethereumj-core/build.gradle +++ b/ethereumj-core/build.gradle @@ -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}" diff --git a/ethereumj-core/src/main/java/org/ethereum/Start.java b/ethereumj-core/src/main/java/org/ethereum/Start.java new file mode 100644 index 00000000..85b8c135 --- /dev/null +++ b/ethereumj-core/src/main/java/org/ethereum/Start.java @@ -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(); + } + +} diff --git a/ethereumj-core/src/main/java/org/ethereum/config/SystemProperties.java b/ethereumj-core/src/main/java/org/ethereum/config/SystemProperties.java index a502eacd..a0a96494 100644 --- a/ethereumj-core/src/main/java/org/ethereum/config/SystemProperties.java +++ b/ethereumj-core/src/main/java/org/ethereum/config/SystemProperties.java @@ -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"; diff --git a/ethereumj-core/src/main/java/org/ethereum/core/BlockchainImpl.java b/ethereumj-core/src/main/java/org/ethereum/core/BlockchainImpl.java index 44ee7276..e3ed2735 100644 --- a/ethereumj-core/src/main/java/org/ethereum/core/BlockchainImpl.java +++ b/ethereumj-core/src/main/java/org/ethereum/core/BlockchainImpl.java @@ -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; } - -} \ No newline at end of file +} diff --git a/ethereumj-core/src/main/java/org/ethereum/core/TransactionExecutor.java b/ethereumj-core/src/main/java/org/ethereum/core/TransactionExecutor.java index 329e607a..3bbfae07 100644 --- a/ethereumj-core/src/main/java/org/ethereum/core/TransactionExecutor.java +++ b/ethereumj-core/src/main/java/org/ethereum/core/TransactionExecutor.java @@ -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) { diff --git a/ethereumj-core/src/main/java/org/ethereum/core/Wallet.java b/ethereumj-core/src/main/java/org/ethereum/core/Wallet.java index 28843760..bdc6826b 100644 --- a/ethereumj-core/src/main/java/org/ethereum/core/Wallet.java +++ b/ethereumj-core/src/main/java/org/ethereum/core/Wallet.java @@ -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; } -} \ No newline at end of file +} diff --git a/ethereumj-core/src/main/java/org/ethereum/datasource/AndroidLevelDbDataSource.java b/ethereumj-core/src/main/java/org/ethereum/datasource/AndroidLevelDbDataSource.java new file mode 100644 index 00000000..9d146eea --- /dev/null +++ b/ethereumj-core/src/main/java/org/ethereum/datasource/AndroidLevelDbDataSource.java @@ -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 keys() { + + DBIterator dbIterator = db.iterator(); + Set keys = new HashSet<>(); + while (dbIterator.hasNext()) { + + Map.Entry entry = dbIterator.next(); + keys.add(entry.getKey()); + } + return keys; + } + + @Override + public void updateBatch(Map rows) { + + WriteBatch batch = db.createWriteBatch(); + + for (Map.Entry 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); + } + } +} \ No newline at end of file diff --git a/ethereumj-core/src/main/java/org/ethereum/datasource/LevelDbDataSource.java b/ethereumj-core/src/main/java/org/ethereum/datasource/LevelDbDataSource.java index 663898ca..d18e2426 100644 --- a/ethereumj-core/src/main/java/org/ethereum/datasource/LevelDbDataSource.java +++ b/ethereumj-core/src/main/java/org/ethereum/datasource/LevelDbDataSource.java @@ -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); } } -} \ No newline at end of file +} diff --git a/ethereumj-core/src/main/java/org/ethereum/di/modules/EthereumModule.java b/ethereumj-core/src/main/java/org/ethereum/di/modules/EthereumModule.java index a66d5d3b..7bcedd68 100644 --- a/ethereumj-core/src/main/java/org/ethereum/di/modules/EthereumModule.java +++ b/ethereumj-core/src/main/java/org/ethereum/di/modules/EthereumModule.java @@ -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(); } -*/ + } diff --git a/ethereumj-core/src/main/java/org/ethereum/facade/CommonConfig.java b/ethereumj-core/src/main/java/org/ethereum/facade/CommonConfig.java index 32f68ad0..1cfe4727 100644 --- a/ethereumj-core/src/main/java/org/ethereum/facade/CommonConfig.java +++ b/ethereumj-core/src/main/java/org/ethereum/facade/CommonConfig.java @@ -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; } */ -} \ No newline at end of file +} diff --git a/ethereumj-core/src/main/java/org/ethereum/jsontestsuite/TestRunner.java b/ethereumj-core/src/main/java/org/ethereum/jsontestsuite/TestRunner.java index 6b34737d..8d503414 100644 --- a/ethereumj-core/src/main/java/org/ethereum/jsontestsuite/TestRunner.java +++ b/ethereumj-core/src/main/java/org/ethereum/jsontestsuite/TestRunner.java @@ -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; } -} \ No newline at end of file +} diff --git a/ethereumj-core/src/main/java/org/ethereum/manager/AdminInfo.java b/ethereumj-core/src/main/java/org/ethereum/manager/AdminInfo.java index e5d5ccaa..b98aefdc 100644 --- a/ethereumj-core/src/main/java/org/ethereum/manager/AdminInfo.java +++ b/ethereumj-core/src/main/java/org/ethereum/manager/AdminInfo.java @@ -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 blockExecTime = new LinkedList<>(); @@ -59,4 +59,4 @@ public class AdminInfo { public List getBlockExecTime(){ return blockExecTime; } -} \ No newline at end of file +} diff --git a/ethereumj-core/src/main/java/org/ethereum/manager/BlockLoader.java b/ethereumj-core/src/main/java/org/ethereum/manager/BlockLoader.java index e8c088bf..3a7a597f 100644 --- a/ethereumj-core/src/main/java/org/ethereum/manager/BlockLoader.java +++ b/ethereumj-core/src/main/java/org/ethereum/manager/BlockLoader.java @@ -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 { } -} \ No newline at end of file + + +} diff --git a/ethereumj-core/src/main/java/org/ethereum/manager/WorldManager.java b/ethereumj-core/src/main/java/org/ethereum/manager/WorldManager.java index db8a58db..4917682a 100644 --- a/ethereumj-core/src/main/java/org/ethereum/manager/WorldManager.java +++ b/ethereumj-core/src/main/java/org/ethereum/manager/WorldManager.java @@ -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(); } -} \ No newline at end of file +} diff --git a/ethereumj-core/src/main/java/org/ethereum/net/message/ReasonCode.java b/ethereumj-core/src/main/java/org/ethereum/net/message/ReasonCode.java index c6a4901a..4444d804 100644 --- a/ethereumj-core/src/main/java/org/ethereum/net/message/ReasonCode.java +++ b/ethereumj-core/src/main/java/org/ethereum/net/message/ReasonCode.java @@ -34,6 +34,7 @@ public enum ReasonCode { */ TOO_MANY_PEERS(0x04), + /** * [0x05] Already have a running connection with this peer */ diff --git a/ethereumj-core/src/main/java/org/ethereum/net/server/EthereumChannelInitializer.java b/ethereumj-core/src/main/java/org/ethereum/net/server/EthereumChannelInitializer.java index 64ea18f2..e350f7a4 100644 --- a/ethereumj-core/src/main/java/org/ethereum/net/server/EthereumChannelInitializer.java +++ b/ethereumj-core/src/main/java/org/ethereum/net/server/EthereumChannelInitializer.java @@ -38,12 +38,12 @@ public class EthereumChannelInitializer extends ChannelInitializer channelProvider; @Inject - public EthereumChannelInitializer(Blockchain blockchain, ChannelManager channelManager, Provider channelProvider) { + public EthereumChannelInitializer(Blockchain blockchain, ChannelManager channelManager, Provider 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 { 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 { super(); this.listener = listener; } - +*/ @Override protected void decode(ChannelHandlerContext ctx, ByteBuf in, List out) throws Exception { if (!isHandshakeDone) @@ -99,7 +119,7 @@ public class MessageCodec extends ByteToMessageCodec { 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 { 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); diff --git a/ethereumj-core/src/main/java/org/ethereum/vm/Memory.java b/ethereumj-core/src/main/java/org/ethereum/vm/Memory.java new file mode 100644 index 00000000..aebd80b2 --- /dev/null +++ b/ethereumj-core/src/main/java/org/ethereum/vm/Memory.java @@ -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 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 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]); + } + } +} diff --git a/ethereumj-core/src/main/java/org/ethereum/vm/Program.java b/ethereumj-core/src/main/java/org/ethereum/vm/Program.java index c9fab5b0..0e29c463 100644 --- a/ethereumj-core/src/main/java/org/ethereum/vm/Program.java +++ b/ethereumj-core/src/main/java/org/ethereum/vm/Program.java @@ -84,7 +84,7 @@ public class Program { precompile(); } } - + private 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 { } -} +} \ No newline at end of file diff --git a/ethereumj-core/src/main/java/org/ethereum/vm/ProgramTraceListenerAware.java b/ethereumj-core/src/main/java/org/ethereum/vm/ProgramTraceListenerAware.java new file mode 100644 index 00000000..d59b8142 --- /dev/null +++ b/ethereumj-core/src/main/java/org/ethereum/vm/ProgramTraceListenerAware.java @@ -0,0 +1,8 @@ +package org.ethereum.vm; + +import org.ethereum.vmtrace.ProgramTraceListener; + +public interface ProgramTraceListenerAware { + + void setTraceListener(ProgramTraceListener listener); +} diff --git a/ethereumj-core/src/main/java/org/ethereum/vm/Stack.java b/ethereumj-core/src/main/java/org/ethereum/vm/Stack.java new file mode 100644 index 00000000..c4448e7f --- /dev/null +++ b/ethereumj-core/src/main/java/org/ethereum/vm/Stack.java @@ -0,0 +1,37 @@ +package org.ethereum.vm; + +import org.ethereum.vmtrace.ProgramTraceListener; + +public class Stack extends java.util.Stack 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(); + } +} diff --git a/ethereumj-core/src/main/java/org/ethereum/vm/Storage.java b/ethereumj-core/src/main/java/org/ethereum/vm/Storage.java new file mode 100644 index 00000000..eee8f8c5 --- /dev/null +++ b/ethereumj-core/src/main/java/org/ethereum/vm/Storage.java @@ -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 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 accountStates, HashMap 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 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 cacheAccounts, HashMap cacheDetails) { + repository.loadAccount(addr, cacheAccounts, cacheDetails); + } +} diff --git a/ethereumj-core/src/main/java/org/ethereum/vm/VMUtils.java b/ethereumj-core/src/main/java/org/ethereum/vm/VMUtils.java new file mode 100644 index 00000000..0517bdb1 --- /dev/null +++ b/ethereumj-core/src/main/java/org/ethereum/vm/VMUtils.java @@ -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; + } + } +} diff --git a/ethereumj-core/src/main/java/org/ethereum/vmtrace/OpActions.java b/ethereumj-core/src/main/java/org/ethereum/vmtrace/OpActions.java new file mode 100644 index 00000000..0d3394d8 --- /dev/null +++ b/ethereumj-core/src/main/java/org/ethereum/vmtrace/OpActions.java @@ -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 params; + + public Name getName() { + return name; + } + + public void setName(Name name) { + this.name = name; + } + + public Map getParams() { + return params; + } + + public void setParams(Map 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 stack = new ArrayList<>(); + private List memory = new ArrayList<>(); + private List storage = new ArrayList<>(); + + public List getStack() { + return stack; + } + + public void setStack(List stack) { + this.stack = stack; + } + + public List getMemory() { + return memory; + } + + public void setMemory(List memory) { + this.memory = memory; + } + + public List getStorage() { + return storage; + } + + public void setStorage(List storage) { + this.storage = storage; + } + + private static Action addAction(List 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); + } +} diff --git a/ethereumj-core/src/main/java/org/ethereum/vmtrace/ProgramTraceListener.java b/ethereumj-core/src/main/java/org/ethereum/vmtrace/ProgramTraceListener.java new file mode 100644 index 00000000..deb2e9f7 --- /dev/null +++ b/ethereumj-core/src/main/java/org/ethereum/vmtrace/ProgramTraceListener.java @@ -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; + } +} diff --git a/ethereumj-core/src/main/resources/system.properties b/ethereumj-core/src/main/resources/system.properties index 15f25f7b..cdc4f4a4 100644 --- a/ethereumj-core/src/main/resources/system.properties +++ b/ethereumj-core/src/main/resources/system.properties @@ -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= \ No newline at end of file