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 37d9b3ce..24712802 100644 --- a/ethereumj-core/src/main/java/org/ethereum/config/SystemProperties.java +++ b/ethereumj-core/src/main/java/org/ethereum/config/SystemProperties.java @@ -45,6 +45,7 @@ public class SystemProperties { private final static int DEFAULT_PEER_LISTEN_PORT = 30303; private final static String DEFAULT_KEY_VALUE_DATA_SOURCE = "leveldb"; private final static boolean DEFAULT_REDIS_ENABLED = true; + private static final String DEFAULT_BLOCKS_LOADER = ""; /* Testing */ @@ -288,6 +289,11 @@ public class SystemProperties { return Boolean.parseBoolean(prop.getProperty("GitHubTests.VMTest.loadLocal", String.valueOf(DEFAULT_VMTEST_LOAD_LOCAL))); } + public String blocksLoader() { + return prop.getProperty("blocks.loader", DEFAULT_BLOCKS_LOADER); + } + + public static void main(String args[]) { SystemProperties systemProperties = new SystemProperties(); systemProperties.print(); 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 59e84bdb..78feae81 100644 --- a/ethereumj-core/src/main/java/org/ethereum/core/BlockchainImpl.java +++ b/ethereumj-core/src/main/java/org/ethereum/core/BlockchainImpl.java @@ -563,19 +563,19 @@ public class BlockchainImpl implements Blockchain { public void storeBlock(Block block, List receipts) { /* Debug check to see if the state is still as expected */ - if (logger.isWarnEnabled()) { - String blockStateRootHash = Hex.toHexString(block.getStateRoot()); - String worldStateRootHash = Hex.toHexString(repository.getRoot()); - if (!blockStateRootHash.equals(worldStateRootHash)) { + String blockStateRootHash = Hex.toHexString(block.getStateRoot()); + String worldStateRootHash = Hex.toHexString(repository.getRoot()); + if (!blockStateRootHash.equals(worldStateRootHash)) { - stateLogger.error("BLOCK: STATE CONFLICT! block: {} worldstate {} mismatch", block.getNumber(), worldStateRootHash); - adminInfo.lostConsensus(); + stateLogger.error("BLOCK: STATE CONFLICT! block: {} worldstate {} mismatch", block.getNumber(), worldStateRootHash); + adminInfo.lostConsensus(); - // in case of rollback hard move the root + System.out.println("CONFLICT: BLOCK #" + block.getNumber() ); + System.exit(1); + // in case of rollback hard move the root // Block parentBlock = blockStore.getBlockByHash(block.getParentHash()); // repository.syncToRoot(parentBlock.getStateRoot()); - // todo: after the rollback happens other block should be requested - } + // todo: after the rollback happens other block should be requested } blockStore.saveBlock(block, receipts); 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 547a4ab2..992c8740 100644 --- a/ethereumj-core/src/main/java/org/ethereum/core/TransactionExecutor.java +++ b/ethereumj-core/src/main/java/org/ethereum/core/TransactionExecutor.java @@ -1,5 +1,6 @@ package org.ethereum.core; +//import jdk.jfr.events.ThrowablesEvent; import org.ethereum.db.BlockStore; import org.ethereum.facade.Repository; import org.ethereum.listener.EthereumListener; @@ -181,13 +182,18 @@ public class TransactionExecutor { private void create() { byte[] newContractAddress = tx.getContractAddress(); - if (!(tx.getData().length == 0)){ + if (tx.getData() != null && !(tx.getData().length == 0)){ ProgramInvoke programInvoke = programInvokeFactory.createProgramInvoke(tx, currentBlock, cacheTrack, blockStore); this.vm = new VM(); this.program = new Program(tx.getData(), programInvoke); + } else { + + + m_endGas = toBI(tx.getGasLimit()).longValue() - basicTxCost; + cacheTrack.createAccount(tx.getContractAddress()); } BigInteger endowment = toBI(tx.getValue()); 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 7925f41e..0d61ee09 100644 --- a/ethereumj-core/src/main/java/org/ethereum/core/Wallet.java +++ b/ethereumj-core/src/main/java/org/ethereum/core/Wallet.java @@ -368,4 +368,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/redis/RedisConnectionImpl.java b/ethereumj-core/src/main/java/org/ethereum/datasource/redis/RedisConnectionImpl.java index c6bdeed9..5f31c94d 100644 --- a/ethereumj-core/src/main/java/org/ethereum/datasource/redis/RedisConnectionImpl.java +++ b/ethereumj-core/src/main/java/org/ethereum/datasource/redis/RedisConnectionImpl.java @@ -29,7 +29,7 @@ public class RedisConnectionImpl implements RedisConnection { if (!SystemProperties.CONFIG.isRedisEnabled()) return; String redisCloudUrl = System.getenv(REDISCLOUD_URL); - if (hasLength(redisCloudUrl)) { + if (!hasLength(redisCloudUrl)) { logger.info("Cannot connect to Redis. 'REDISCLOUD_URL' environment variable is not defined."); return; } diff --git a/ethereumj-core/src/main/java/org/ethereum/db/BlockStore.java b/ethereumj-core/src/main/java/org/ethereum/db/BlockStore.java index 6c02e6f4..0318f919 100644 --- a/ethereumj-core/src/main/java/org/ethereum/db/BlockStore.java +++ b/ethereumj-core/src/main/java/org/ethereum/db/BlockStore.java @@ -17,37 +17,27 @@ public interface BlockStore { public byte[] getBlockHashByNumber(long blockNumber); - //@Transactional(readOnly = true) Block getBlockByNumber(long blockNumber); - //@Transactional(readOnly = true) Block getBlockByHash(byte[] hash); - //@Transactional(readOnly = true) @SuppressWarnings("unchecked") List getListOfHashesStartFrom(byte[] hash, int qty); - //@Transactional void deleteBlocksSince(long number); - //@Transactional void saveBlock(Block block, List receipts); - //@Transactional(readOnly = true) BigInteger getTotalDifficultySince(long number); - //@Transactional(readOnly = true) BigInteger getTotalDifficulty(); - //@Transactional(readOnly = true) Block getBestBlock(); - //@Transactional(readOnly = true) @SuppressWarnings("unchecked") List getAllBlocks(); - //@Transactional void reset(); TransactionReceipt getTransactionReceiptByHash(byte[] hash); -} \ No newline at end of file +} diff --git a/ethereumj-core/src/main/java/org/ethereum/db/BlockStoreImpl.java b/ethereumj-core/src/main/java/org/ethereum/db/BlockStoreImpl.java new file mode 100644 index 00000000..40f4133a --- /dev/null +++ b/ethereumj-core/src/main/java/org/ethereum/db/BlockStoreImpl.java @@ -0,0 +1,194 @@ +package org.ethereum.db; + +import org.ethereum.core.Block; +import org.ethereum.core.TransactionReceipt; +import org.ethereum.util.ByteUtil; + +import org.hibernate.SessionFactory; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; +import org.springframework.stereotype.Repository; +import org.springframework.transaction.annotation.Propagation; +import org.springframework.transaction.annotation.Transactional; + +import java.math.BigInteger; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author Roman Mandeleil + * @since 12.11.2014 + */ +public class BlockStoreImpl implements BlockStore { + + private SessionFactory sessionFactory; + + public BlockStoreImpl(SessionFactory sessionFactory) { + this.sessionFactory = sessionFactory; + } + + @Override + @Transactional(readOnly = true) + public byte[] getBlockHashByNumber(long blockNumber) { + + Block block = getBlockByNumber(blockNumber); + if (block != null) return block.getHash(); + return ByteUtil.EMPTY_BYTE_ARRAY; + } + + @Override + @Transactional(readOnly = true) + public Block getBlockByNumber(long blockNumber) { + + List result = sessionFactory.getCurrentSession(). + createQuery("from BlockVO where number = :number"). + setParameter("number", blockNumber).list(); + + if (result.size() == 0) return null; + BlockVO vo = (BlockVO) result.get(0); + + return new Block(vo.rlp); + } + + @Override + @Transactional(readOnly = true) + public Block getBlockByHash(byte[] hash) { + + List result = sessionFactory.getCurrentSession(). + createQuery("from BlockVO where hash = :hash"). + setParameter("hash", hash).list(); + + if (result.size() == 0) return null; + BlockVO vo = (BlockVO) result.get(0); + + return new Block(vo.rlp); + } + + @Override + @Transactional(readOnly = true) + @SuppressWarnings("unchecked") + public List getListOfHashesStartFrom(byte[] hash, int qty) { + + List hashes = new ArrayList<>(); + + // find block number of that block hash + Block block = getBlockByHash(hash); + if (block == null) return hashes; + + List result = sessionFactory.getCurrentSession(). + createQuery("select hash from BlockVO where number <= :number and number >= :limit order by number desc"). + setParameter("number", block.getNumber()). + setParameter("limit", block.getNumber() - qty). + setMaxResults(qty).list(); + + for (byte[] h : result) + hashes.add(h); + + return hashes; + } + + @Override + @Transactional + public void deleteBlocksSince(long number) { + + sessionFactory.getCurrentSession(). + createQuery("delete from BlockVO where number > :number"). + setParameter("number", number). + executeUpdate(); + } + + + @Override + @Transactional + public void saveBlock(Block block, List receipts) { + + BlockVO blockVO = new BlockVO(block.getNumber(), block.getHash(), + block.getEncoded(), block.getCumulativeDifficulty()); + + for (TransactionReceipt receipt : receipts) { + + byte[] hash = receipt.getTransaction().getHash(); + byte[] rlp = receipt.getEncoded(); + + TransactionReceiptVO transactionReceiptVO = new TransactionReceiptVO(hash, rlp); + sessionFactory.getCurrentSession().persist(transactionReceiptVO); + } + + sessionFactory.getCurrentSession().persist(blockVO); + } + + @Override + @Transactional(readOnly = true) + public BigInteger getTotalDifficultySince(long number) { + + return (BigInteger) sessionFactory.getCurrentSession(). + createQuery("select sum(cumulativeDifficulty) from BlockVO where number > :number"). + setParameter("number", number). + uniqueResult(); + } + + + @Override + @Transactional(readOnly = true) + public BigInteger getTotalDifficulty() { + + return (BigInteger) sessionFactory.getCurrentSession(). + createQuery("select sum(cumulativeDifficulty) from BlockVO").uniqueResult(); + } + + + @Override + @Transactional(readOnly = true) + public Block getBestBlock() { + + Long bestNumber = (Long) + sessionFactory.getCurrentSession().createQuery("select max(number) from BlockVO").uniqueResult(); + List result = sessionFactory.getCurrentSession(). + createQuery("from BlockVO where number = :number").setParameter("number", bestNumber).list(); + + if (result.isEmpty()) return null; + BlockVO vo = (BlockVO) result.get(0); + + return new Block(vo.rlp); + } + + @Override + @Transactional(readOnly = true) + @SuppressWarnings("unchecked") + public List getAllBlocks() { + + List result = sessionFactory.getCurrentSession(). + createQuery("from BlockVO").list(); + + ArrayList blocks = new ArrayList<>(); + for (BlockVO blockVO : result) { + blocks.add(new Block(blockVO.getRlp())); + } + + return blocks; + } + + @Override + @Transactional + public void reset() { + sessionFactory.getCurrentSession(). + createQuery("delete from BlockVO").executeUpdate(); + } + + @Override + @Transactional(readOnly = true) + public TransactionReceipt getTransactionReceiptByHash(byte[] hash) { + + List result = sessionFactory.getCurrentSession(). + createQuery("from TransactionReceiptVO where hash = :hash"). + setParameter("hash", hash).list(); + + if (result.size() == 0) return null; + TransactionReceiptVO vo = (TransactionReceiptVO) result.get(0); + + return new TransactionReceipt(vo.rlp); + + } +} diff --git a/ethereumj-core/src/main/java/org/ethereum/db/RepositoryDummy.java b/ethereumj-core/src/main/java/org/ethereum/db/RepositoryDummy.java index af2fa412..0d47c99d 100644 --- a/ethereumj-core/src/main/java/org/ethereum/db/RepositoryDummy.java +++ b/ethereumj-core/src/main/java/org/ethereum/db/RepositoryDummy.java @@ -301,4 +301,4 @@ public class RepositoryDummy extends RepositoryImpl { cacheAccounts.put(wrap(addr), account); cacheDetails.put(wrap(addr), details); } -} +} \ No newline at end of file diff --git a/ethereumj-core/src/main/java/org/ethereum/db/RepositoryImpl.java b/ethereumj-core/src/main/java/org/ethereum/db/RepositoryImpl.java index d369da48..10963f38 100644 --- a/ethereumj-core/src/main/java/org/ethereum/db/RepositoryImpl.java +++ b/ethereumj-core/src/main/java/org/ethereum/db/RepositoryImpl.java @@ -486,4 +486,4 @@ public class RepositoryImpl implements Repository { public byte[] getRoot() { return worldState.getRootHash(); } -} +} \ No newline at end of file diff --git a/ethereumj-core/src/main/java/org/ethereum/db/RepositoryTrack.java b/ethereumj-core/src/main/java/org/ethereum/db/RepositoryTrack.java index c6c3f2f8..e7645a19 100644 --- a/ethereumj-core/src/main/java/org/ethereum/db/RepositoryTrack.java +++ b/ethereumj-core/src/main/java/org/ethereum/db/RepositoryTrack.java @@ -287,4 +287,4 @@ public class RepositoryTrack implements Repository { throw new UnsupportedOperationException(); } -} +} \ No newline at end of file diff --git a/ethereumj-core/src/main/java/org/ethereum/db/RepositoryVMTestDummy.java b/ethereumj-core/src/main/java/org/ethereum/db/RepositoryVMTestDummy.java index 34c4a9fd..d2170a1d 100644 --- a/ethereumj-core/src/main/java/org/ethereum/db/RepositoryVMTestDummy.java +++ b/ethereumj-core/src/main/java/org/ethereum/db/RepositoryVMTestDummy.java @@ -302,4 +302,4 @@ public class RepositoryVMTestDummy extends RepositoryImpl{ cacheAccounts.put(wrap(addr), account); cacheDetails.put(wrap(addr), details); } -} +} \ No newline at end of file diff --git a/ethereumj-core/src/main/java/org/ethereum/facade/Ethereum.java b/ethereumj-core/src/main/java/org/ethereum/facade/Ethereum.java index 23287dea..fcdc8da1 100644 --- a/ethereumj-core/src/main/java/org/ethereum/facade/Ethereum.java +++ b/ethereumj-core/src/main/java/org/ethereum/facade/Ethereum.java @@ -4,16 +4,14 @@ import org.ethereum.core.Transaction; import org.ethereum.core.Wallet; import org.ethereum.listener.EthereumListener; import org.ethereum.manager.AdminInfo; +import org.ethereum.manager.BlockLoader; import org.ethereum.net.client.PeerClient; import org.ethereum.net.peerdiscovery.PeerInfo; -import org.ethereum.net.rlpx.FrameCodec; import org.ethereum.net.server.ChannelManager; import org.springframework.context.ApplicationContext; import java.math.BigInteger; - import java.net.InetAddress; - import java.util.Set; import java.util.concurrent.Future; @@ -139,5 +137,5 @@ public interface Ethereum { public Set getPendingTransactions(); - + public BlockLoader getBlockLoader(); } diff --git a/ethereumj-core/src/main/java/org/ethereum/facade/EthereumFactory.java b/ethereumj-core/src/main/java/org/ethereum/facade/EthereumFactory.java index a13b1e43..2d29da0d 100644 --- a/ethereumj-core/src/main/java/org/ethereum/facade/EthereumFactory.java +++ b/ethereumj-core/src/main/java/org/ethereum/facade/EthereumFactory.java @@ -33,4 +33,4 @@ public class EthereumFactory { return context.getBean(Ethereum.class); } -} +} \ No newline at end of file diff --git a/ethereumj-core/src/main/java/org/ethereum/facade/EthereumImpl.java b/ethereumj-core/src/main/java/org/ethereum/facade/EthereumImpl.java index 19ed0bec..3084593b 100644 --- a/ethereumj-core/src/main/java/org/ethereum/facade/EthereumImpl.java +++ b/ethereumj-core/src/main/java/org/ethereum/facade/EthereumImpl.java @@ -4,10 +4,10 @@ import org.ethereum.core.Transaction; import org.ethereum.core.Wallet; import org.ethereum.listener.EthereumListener; import org.ethereum.manager.AdminInfo; +import org.ethereum.manager.BlockLoader; import org.ethereum.manager.WorldManager; import org.ethereum.net.client.PeerClient; import org.ethereum.net.peerdiscovery.PeerInfo; -import org.ethereum.net.rlpx.FrameCodec; import org.ethereum.net.server.ChannelManager; import org.ethereum.net.server.PeerServer; import org.ethereum.net.submit.TransactionExecutor; @@ -55,6 +55,9 @@ public class EthereumImpl implements Ethereum { @Autowired ApplicationContext ctx; + @Autowired + BlockLoader blockLoader; + public EthereumImpl() { System.out.println(); logger.info("EthereumImpl constructor"); @@ -253,5 +256,8 @@ public class EthereumImpl implements Ethereum { return getBlockchain().getPendingTransactions(); } - + @Override + public BlockLoader getBlockLoader(){ + return blockLoader; + } } diff --git a/ethereumj-core/src/main/java/org/ethereum/jsontestsuite/JSONReader.java b/ethereumj-core/src/main/java/org/ethereum/jsontestsuite/JSONReader.java index 6c859132..0a725ac8 100644 --- a/ethereumj-core/src/main/java/org/ethereum/jsontestsuite/JSONReader.java +++ b/ethereumj-core/src/main/java/org/ethereum/jsontestsuite/JSONReader.java @@ -134,4 +134,4 @@ public class JSONReader { return fileNames; } -} +} \ No newline at end of file diff --git a/ethereumj-core/src/main/java/org/ethereum/jsontestsuite/runners/StateTestRunner.java b/ethereumj-core/src/main/java/org/ethereum/jsontestsuite/runners/StateTestRunner.java index b897e981..90bf8141 100644 --- a/ethereumj-core/src/main/java/org/ethereum/jsontestsuite/runners/StateTestRunner.java +++ b/ethereumj-core/src/main/java/org/ethereum/jsontestsuite/runners/StateTestRunner.java @@ -92,4 +92,4 @@ public class StateTestRunner { logger.info("\n\n"); return results; } -} +} \ No newline at end of file diff --git a/ethereumj-core/src/main/java/org/ethereum/listener/CompositeEthereumListener.java b/ethereumj-core/src/main/java/org/ethereum/listener/CompositeEthereumListener.java index 50f6ffe6..846c65fb 100644 --- a/ethereumj-core/src/main/java/org/ethereum/listener/CompositeEthereumListener.java +++ b/ethereumj-core/src/main/java/org/ethereum/listener/CompositeEthereumListener.java @@ -94,4 +94,4 @@ public class CompositeEthereumListener implements EthereumListener { listeners.add(listener); } -} +} \ 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 0105fbc4..2a64e94e 100644 --- a/ethereumj-core/src/main/java/org/ethereum/manager/AdminInfo.java +++ b/ethereumj-core/src/main/java/org/ethereum/manager/AdminInfo.java @@ -56,4 +56,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 new file mode 100644 index 00000000..c18c3db1 --- /dev/null +++ b/ethereumj-core/src/main/java/org/ethereum/manager/BlockLoader.java @@ -0,0 +1,55 @@ +package org.ethereum.manager; + + +import org.ethereum.core.Block; +import org.ethereum.facade.Blockchain; +import org.ethereum.net.BlockQueue; +import org.spongycastle.util.encoders.Hex; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.io.File; +import java.io.IOException; +import java.net.URISyntaxException; +import java.net.URL; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.util.List; + +import static org.ethereum.config.SystemProperties.CONFIG; + +@Component +public class BlockLoader { + + @Autowired + private Blockchain blockchain; + + + public void loadBlocks(){ + + String fileSrc = CONFIG.blocksLoader(); + try { + File blocksFile = new File(fileSrc); + System.out.println("Loading blocks: " + fileSrc); + List blocksList = Files.readAllLines(blocksFile.toPath(), StandardCharsets.UTF_8); + + for (String blockRLP : blocksList){ + + byte[] blockRLPBytes = Hex.decode( blockRLP ); + Block block = new Block(blockRLPBytes); + + if (block.getNumber() > blockchain.getBestBlock().getNumber()){ + System.out.println("Importing block #" + block.getNumber()); + blockchain.tryToConnect(block); + } else + System.out.println("Skipping block #" + block.getNumber()); + + + } + } catch (IOException e) { + e.printStackTrace(); + } + + + } +} 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 1c8ca342..ec1a5673 100644 --- a/ethereumj-core/src/main/java/org/ethereum/manager/WorldManager.java +++ b/ethereumj-core/src/main/java/org/ethereum/manager/WorldManager.java @@ -212,4 +212,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/BlockQueue.java b/ethereumj-core/src/main/java/org/ethereum/net/BlockQueue.java index 271e708b..3ce2307f 100644 --- a/ethereumj-core/src/main/java/org/ethereum/net/BlockQueue.java +++ b/ethereumj-core/src/main/java/org/ethereum/net/BlockQueue.java @@ -281,4 +281,4 @@ public class BlockQueue { } -} +} \ No newline at end of file diff --git a/ethereumj-core/src/main/java/org/ethereum/net/MessageQueue.java b/ethereumj-core/src/main/java/org/ethereum/net/MessageQueue.java index d0ffe1ae..8ea3d18c 100644 --- a/ethereumj-core/src/main/java/org/ethereum/net/MessageQueue.java +++ b/ethereumj-core/src/main/java/org/ethereum/net/MessageQueue.java @@ -132,4 +132,4 @@ public class MessageQueue { timer.cancel(); timer.purge(); } -} +} \ No newline at end of file diff --git a/ethereumj-core/src/main/java/org/ethereum/net/client/PeerClient.java b/ethereumj-core/src/main/java/org/ethereum/net/client/PeerClient.java index 0ff9259d..91adab41 100644 --- a/ethereumj-core/src/main/java/org/ethereum/net/client/PeerClient.java +++ b/ethereumj-core/src/main/java/org/ethereum/net/client/PeerClient.java @@ -54,6 +54,7 @@ public class PeerClient { worldManager.getListener().trace("Connecting to: " + host + ":" + port); EthereumChannelInitializer ethereumChannelInitializer = (EthereumChannelInitializer)ctx.getBean("ethereumChannelInitializer", EthereumChannelInitializer.class); + ethereumChannelInitializer.setRemoteId(remoteId); try { Bootstrap b = new Bootstrap(); diff --git a/ethereumj-core/src/main/java/org/ethereum/net/peerdiscovery/DiscoveryChannel.java b/ethereumj-core/src/main/java/org/ethereum/net/peerdiscovery/DiscoveryChannel.java index 6be5025a..e34142fe 100644 --- a/ethereumj-core/src/main/java/org/ethereum/net/peerdiscovery/DiscoveryChannel.java +++ b/ethereumj-core/src/main/java/org/ethereum/net/peerdiscovery/DiscoveryChannel.java @@ -139,4 +139,4 @@ public class DiscoveryChannel { public StatusMessage getStatusHandshake() { return ethHandler.getHandshakeStatusMessage(); } -} +} \ No newline at end of file diff --git a/ethereumj-core/src/main/java/org/ethereum/net/peerdiscovery/WorkerThread.java b/ethereumj-core/src/main/java/org/ethereum/net/peerdiscovery/WorkerThread.java index d9eb3a20..fe42ba84 100644 --- a/ethereumj-core/src/main/java/org/ethereum/net/peerdiscovery/WorkerThread.java +++ b/ethereumj-core/src/main/java/org/ethereum/net/peerdiscovery/WorkerThread.java @@ -85,4 +85,4 @@ public class WorkerThread implements Runnable { public String toString() { return "Worker for: " + this.peerInfo.toString(); } -} +} \ No newline at end of file diff --git a/ethereumj-core/src/main/java/org/ethereum/net/server/Channel.java b/ethereumj-core/src/main/java/org/ethereum/net/server/Channel.java index 6d725e67..98627a7a 100644 --- a/ethereumj-core/src/main/java/org/ethereum/net/server/Channel.java +++ b/ethereumj-core/src/main/java/org/ethereum/net/server/Channel.java @@ -157,4 +157,4 @@ public class Channel { public void setInetSocketAddress(InetSocketAddress inetSocketAddress) { this.inetSocketAddress = inetSocketAddress; } -} +} \ No newline at end of file diff --git a/ethereumj-core/src/main/java/org/ethereum/net/server/ChannelManager.java b/ethereumj-core/src/main/java/org/ethereum/net/server/ChannelManager.java index a0c00f97..82773a91 100644 --- a/ethereumj-core/src/main/java/org/ethereum/net/server/ChannelManager.java +++ b/ethereumj-core/src/main/java/org/ethereum/net/server/ChannelManager.java @@ -141,4 +141,4 @@ public class ChannelManager { public List getChannels() { return channels; } -} +} \ No newline at end of file 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 03f09d2d..a652fea7 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 @@ -79,4 +79,8 @@ public class EthereumChannelInitializer extends ChannelInitializer { public DataWord(byte[] data) { if (data == null) this.data = ByteUtil.EMPTY_BYTE_ARRAY; + else if (data.length == 32) + this.data = data; else if (data.length <= 32) System.arraycopy(data, 0, this.data, 32 - data.length, data.length); else @@ -84,10 +86,14 @@ public class DataWord implements Comparable { * @throws ArithmeticException - if this will not fit in an int. */ public int intValue() { - BigDecimal tmpValue = new BigDecimal(this.value()); - if (this.bytesOccupied() > 4) - return Integer.MAX_VALUE; - return tmpValue.intValueExact(); + int intVal = 0; + + for (int i = 0; i < data.length; i++) + { + intVal = (intVal << 8) + (data[i] & 0xff); + } + + return intVal; } /** @@ -99,10 +105,17 @@ public class DataWord implements Comparable { * @throws ArithmeticException - if this will not fit in a long. */ public long longValue() { - BigDecimal tmpValue = new BigDecimal(this.value()); - return tmpValue.longValueExact(); + + long longVal = 0; + for (int i = 0; i < data.length; i++) + { + longVal = (longVal << 8) + (data[i] & 0xff); + } + + return longVal; } + public BigInteger sValue() { return new BigInteger(data); } diff --git a/ethereumj-core/src/main/java/org/ethereum/vm/MemoryBuffer.java b/ethereumj-core/src/main/java/org/ethereum/vm/MemoryBuffer.java new file mode 100644 index 00000000..86ae519b --- /dev/null +++ b/ethereumj-core/src/main/java/org/ethereum/vm/MemoryBuffer.java @@ -0,0 +1,209 @@ +package org.ethereum.vm; + +import org.ethereum.util.ByteUtil; + +import java.util.LinkedList; + +import static java.lang.String.format; + +public class MemoryBuffer { + + int CHUNK_SIZE = 1024; + + LinkedList chunks = new LinkedList(); + int memorySoftSize = 0; + + public MemoryBuffer() { + } + + public void memorySave(int address, byte[] data) { + + ensureAvailable(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; + } + + memorySoftSize = Math.max(memorySoftSize, (int) Math.ceil((double) (address + data.length) / 32) * 32); + } + + public void memorySave(int address, int allocSize, byte[] value){ + memoryExpand(address, allocSize); + memorySave(address, value); + } + + public DataWord memoryLoad(int address){ + + ensureAvailable(address, 32); + byte[] retData = new byte[32]; + + int chunkIndex = address / CHUNK_SIZE; + int chunkOffset = address % CHUNK_SIZE; + + int toGrab = retData.length; + int start = 0; + + while(toGrab > 0){ + int copied = grabMax(chunkIndex, chunkOffset, toGrab, retData, start); + + // read next chunk from the start + ++chunkIndex; + chunkOffset = 0; + + // mark remind + toGrab -= copied; + start += copied; + } + + memorySoftSize = Math.max(memorySoftSize, (int) Math.ceil((double) (address + retData.length) / 32) * 32); + return new DataWord(retData); + } + + + public void memoryExpand(int offset, int size){ + ensureAvailable(offset, size); + memorySoftSize = Math.max(memorySoftSize,offset + size); + } + + public byte[] memoryChunk(int offset, int size) { + + byte[] data = new byte[size]; + ensureAvailable(offset, size); + + int chunkIndex = offset / CHUNK_SIZE; + int chunkOffset = offset % 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; + } + + memorySoftSize = Math.max(memorySoftSize, (int) Math.ceil((double) (offset + data.length) / 32) * 32); + + return data; + } + + public String memoryToString() { + + StringBuilder memoryData = new StringBuilder(); + StringBuilder firstLine = new StringBuilder(); + StringBuilder secondLine = new StringBuilder(); + + for (int i = 0; i < memorySoftSize; ++i){ + + byte value = getByte(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(ByteUtil.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 < memorySoftSize) memoryData.append("\n"); + firstLine.setLength(0); + secondLine.setLength(0); + } + } + + return memoryData.toString(); + } + + public int getSize(){ + return memorySoftSize; + } + +/*****************************/ +/*****************************/ +/*****************************/ + + // just access expecting all data valid + byte getByte(int address){ + + int chunkIndex = address / CHUNK_SIZE; + int chunkOffset = address % CHUNK_SIZE; + + byte[] chunk = chunks.get(chunkIndex); + + return chunk[chunkOffset]; + } + + + void ensureAvailable(int address, int offset){ + + int memHardSize = getMemoryHardSize(); + int endNewMem = Math.max(memHardSize, address + offset); + + // there is enough mem allocated + if (endNewMem <= memHardSize) return; + + int toAllocate = endNewMem - memHardSize ; + int chunks = (toAllocate % (CHUNK_SIZE) == 0) ? + toAllocate / (CHUNK_SIZE) : + (toAllocate / (CHUNK_SIZE)) + 1; + addChunks(chunks); + } + + int getMemoryHardSize(){ + return chunks.size() * CHUNK_SIZE; + } + + int getMemorySoftSize() { + return memorySoftSize; + } + + int captureMax(int chunkIndex, int chunkOffset, int size, byte[] src, int srcPos){ + + byte[] chunk = chunks.get(chunkIndex); + int toCapture = Math.min(size, chunk.length - chunkOffset); + + System.arraycopy(src, srcPos, chunk, chunkOffset, toCapture); + return toCapture; + } + + int grabMax(int chunkIndex, int chunkOffset, int size, byte[] dest, int destPos) { + + byte[] chunk = chunks.get(chunkIndex); + + int toGrab = Math.min(size, chunk.length - chunkOffset); + System.arraycopy(chunk, chunkOffset, dest, destPos, toGrab); + + return toGrab; + } + + void addChunks(int num){ + for (int i = 0; i < num; ++i) + addChunk(); + } + + void addChunk(){ + 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 9cc612d6..c6ab1223 100644 --- a/ethereumj-core/src/main/java/org/ethereum/vm/Program.java +++ b/ethereumj-core/src/main/java/org/ethereum/vm/Program.java @@ -3,7 +3,6 @@ package org.ethereum.vm; import org.ethereum.crypto.HashUtil; import org.ethereum.db.ContractDetails; import org.ethereum.facade.Repository; -import org.ethereum.util.BIUtil; import org.ethereum.util.ByteUtil; import org.ethereum.vm.MessageCall.MsgType; import org.ethereum.vm.PrecompiledContracts.PrecompiledContract; @@ -54,7 +53,7 @@ public class Program { private ProgramListener listener; Stack stack = new Stack<>(); - ByteBuffer memory = null; + MemoryBuffer memory = new MemoryBuffer(); DataWord programAddress; ProgramResult result = new ProgramResult(); @@ -164,8 +163,8 @@ public class Program { stopped = true; } - public void setHReturn(ByteBuffer buff) { - result.setHReturn(buff.array()); + public void setHReturn(byte[] buff) { + result.setHReturn(buff); } public void step() { @@ -209,15 +208,15 @@ public class Program { } public int getMemSize() { - return memory != null ? memory.limit() : 0; + return memory.getSize(); } public void memorySave(DataWord addrB, DataWord value) { - memorySave(addrB.intValue(), value.getData()); + memory.memorySave(addrB.intValue(), value.getData()); } public void memorySave(int addr, byte[] value) { - memorySave(addr, value.length, value); + memory.memorySave(addr, value); } public void memoryExpand(DataWord outDataOffs, DataWord outDataSize) { @@ -225,10 +224,7 @@ public class Program { if (outDataSize.isZero()) return ; - int maxAddress = outDataOffs.intValue() + outDataSize.intValue(); - if (getMemSize() < maxAddress) { - memorySave(maxAddress, new byte[]{0}); - } + memory.memoryExpand(outDataOffs.intValue(), outDataSize.intValue()); } /** @@ -239,47 +235,20 @@ public class Program { * @param value the data to write to memory */ public void memorySave(int addr, int allocSize, byte[] value) { - - allocateMemory(addr, allocSize); - System.arraycopy(value, 0, memory.array(), addr, value.length); + memory.memorySave(addr, allocSize, value); } public DataWord memoryLoad(DataWord addr) { - return memoryLoad(addr.intValue()); + return memory.memoryLoad(addr.intValue()); } public DataWord memoryLoad(int address) { - allocateMemory(address, DataWord.ZERO.getData().length); - - DataWord newMem = new DataWord(); - System.arraycopy(memory.array(), address, newMem.getData(), 0, newMem.getData().length); - - return newMem; + return memory.memoryLoad(address); } - public ByteBuffer memoryChunk(DataWord offsetData, DataWord sizeData) { - return memoryChunk(offsetData.intValue(), sizeData.intValue()); - } - - /** - * Returns a piece of memory from a given offset and specified size - * If the offset + size exceed the current memory-size, - * the remainder will be filled with empty bytes. - * - * @param offset byte address in memory - * @param size the amount of bytes to return - * @return ByteBuffer containing the chunk of memory data - */ - public ByteBuffer memoryChunk(int offset, int size) { - - allocateMemory(offset, size); - byte[] chunk; - if (memory != null && size != 0) - chunk = Arrays.copyOfRange(memory.array(), offset, offset + size); - else - chunk = new byte[size]; - return ByteBuffer.wrap(chunk); + public byte[] memoryChunk(int offset, int size) { + return memory.memoryChunk(offset, size); } /** @@ -290,14 +259,7 @@ public class Program { * @param size the number of bytes to allocate */ public void allocateMemory(int offset, int size) { - - int memSize = memory != null ? memory.limit() : 0; - double newMemSize = Math.max(memSize, size != 0 ? - Math.ceil((double) (offset + size) / 32) * 32 : 0); - ByteBuffer tmpMem = ByteBuffer.allocate((int) newMemSize); - if (memory != null) - tmpMem.put(memory.array(), 0, memory.limit()); - memory = tmpMem; + memory.memoryExpand(offset, size); } @@ -332,7 +294,7 @@ public class Program { } // [1] FETCH THE CODE FROM THE MEMORY - byte[] programCode = memoryChunk(memStart, memSize).array(); + byte[] programCode = memoryChunk(memStart.intValue(), memSize.intValue()); if (logger.isInfoEnabled()) logger.info("creating a new contract inside contract run: [{}]", Hex.toHexString(senderAddress)); @@ -453,7 +415,7 @@ public class Program { return; } - byte[] data = memoryChunk(msg.getInDataOffs(), msg.getInDataSize()).array(); + byte[] data = memoryChunk(msg.getInDataOffs().intValue(), msg.getInDataSize().intValue()); // FETCH THE SAVED STORAGE byte[] codeAddress = msg.getCodeAddress().getLast20Bytes(); @@ -550,7 +512,7 @@ public class Program { refundGas.toString()); } } else { - this.refundGas(msg.getGas().longValue(), "remaining gas from the internal call"); + this.refundGas(msg.getGas().longValue(), "remaining gas from the internal call"); } } @@ -704,28 +666,7 @@ public class Program { } public String memoryToString() { - StringBuilder memoryData = new StringBuilder(); - StringBuilder firstLine = new StringBuilder(); - StringBuilder secondLine = new StringBuilder(); - for (int i = 0; memory != null && i < memory.limit(); ++i) { - - byte value = memory.get(i); - // Check if value is ASCII - String character = ((byte) 0x20 <= value && value <= (byte) 0x7e) ? new String(new byte[]{value}) : "?"; - firstLine.append(character).append(""); - secondLine.append(ByteUtil.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 < memory.limit()) memoryData.append("\n"); - firstLine.setLength(0); - secondLine.setLength(0); - } - } - return memoryData.toString(); + return memory.memoryToString(); } public void fullTrace() { @@ -737,6 +678,7 @@ public class Program { stackData.append(" ").append(stack.get(i)); if (i < stack.size() - 1) stackData.append("\n"); } + if (stackData.length() > 0) stackData.insert(0, "\n"); ContractDetails contractDetails = this.result.getRepository(). @@ -754,20 +696,26 @@ public class Program { StringBuilder memoryData = new StringBuilder(); StringBuilder oneLine = new StringBuilder(); - for (int i = 0; memory != null && i < memory.limit(); ++i) { + if (memory.getSize() > 32) + memoryData.append("... Memory Folded.... ") + .append("(") + .append(memory.getSize()) + .append(") bytes"); + else + for (int i = 0; i < memory.getSize(); ++i) { - byte value = memory.get(i); - oneLine.append(ByteUtil.oneByteToHexString(value)).append(" "); + byte value = memory.getByte(i); + oneLine.append(ByteUtil.oneByteToHexString(value)).append(" "); - if ((i + 1) % 16 == 0) { - String tmp = format("[%4s]-[%4s]", Integer.toString(i - 15, 16), - Integer.toString(i, 16)).replace(" ", "0"); - memoryData.append("").append(tmp).append(" "); - memoryData.append(oneLine); - if (i < memory.limit()) memoryData.append("\n"); - oneLine.setLength(0); + if ((i + 1) % 16 == 0) { + String tmp = format("[%4s]-[%4s]", Integer.toString(i - 15, 16), + Integer.toString(i, 16)).replace(" ", "0"); + memoryData.append("").append(tmp).append(" "); + memoryData.append(oneLine); + if (i < memory.getSize()) memoryData.append("\n"); + oneLine.setLength(0); + } } - } if (memoryData.length() > 0) memoryData.insert(0, "\n"); StringBuilder opsString = new StringBuilder(); @@ -834,7 +782,7 @@ public class Program { ContractDetails contractDetails = this.result.getRepository(). getContractDetails(this.programAddress.getLast20Bytes()); op.saveStorageMap(contractDetails.getStorage()); - op.saveMemory(memory); + op.saveMemory(memory.memoryChunk(0, memory.getSize())); op.saveStack(stack); programTrace.addOp(op); @@ -842,7 +790,7 @@ public class Program { public void saveProgramTraceToFile(String fileName) { - if (!CONFIG.vmTrace() || hasLength(CONFIG.vmTraceDir())) return; + if (!CONFIG.vmTrace() || !hasLength(CONFIG.vmTraceDir())) return; String dir = CONFIG.databaseDir() + "/" + CONFIG.vmTraceDir() + "/"; @@ -949,7 +897,8 @@ public class Program { return; } - byte[] data = this.memoryChunk(msg.getInDataOffs(), msg.getInDataSize()).array(); + byte[] data = this.memoryChunk(msg.getInDataOffs().intValue(), + msg.getInDataSize().intValue()); transfer(track, senderAddress, codeAddress, msg.getEndowment().value()); @@ -1062,15 +1011,15 @@ public class Program { /** * used mostly for testing reasons */ - public ByteBuffer getMemory() { - return memory; + public byte[] getMemory() { + return memory.memoryChunk(0, memory.getSize()); } /** * used mostly for testing reasons */ - public void initMem(ByteBuffer memory) { - this.memory = memory; + public void initMem(byte[] data) { + this.memory.memorySave(0, data); } diff --git a/ethereumj-core/src/main/java/org/ethereum/vm/ProgramInvokeFactoryImpl.java b/ethereumj-core/src/main/java/org/ethereum/vm/ProgramInvokeFactoryImpl.java index 95046600..7a57b245 100644 --- a/ethereumj-core/src/main/java/org/ethereum/vm/ProgramInvokeFactoryImpl.java +++ b/ethereumj-core/src/main/java/org/ethereum/vm/ProgramInvokeFactoryImpl.java @@ -189,4 +189,4 @@ public class ProgramInvokeFactoryImpl implements ProgramInvokeFactory { public void setBlockchain(Blockchain blockchain) { this.blockchain = blockchain; } -} +} \ No newline at end of file diff --git a/ethereumj-core/src/main/java/org/ethereum/vm/VM.java b/ethereumj-core/src/main/java/org/ethereum/vm/VM.java index fb5433d4..14b520c4 100644 --- a/ethereumj-core/src/main/java/org/ethereum/vm/VM.java +++ b/ethereumj-core/src/main/java/org/ethereum/vm/VM.java @@ -1,21 +1,20 @@ package org.ethereum.vm; -import org.ethereum.crypto.HashUtil; import org.ethereum.db.ContractDetails; -import org.ethereum.util.ByteUtil; import org.ethereum.vm.MessageCall.MsgType; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.spongycastle.util.encoders.Hex; import java.math.BigInteger; -import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Stack; import static org.ethereum.config.SystemProperties.CONFIG; +import static org.ethereum.crypto.HashUtil.sha3; +import static org.ethereum.util.ByteUtil.EMPTY_BYTE_ARRAY; import static org.ethereum.vm.OpCode.*; /** @@ -183,7 +182,7 @@ public class VM { gasCost += GasCost.NEW_ACCT_CALL; //TODO #POC9 Make sure this is converted to BigInteger (256num support) - if (stack.get(stack.size() - 3).intValue() > 0 ) + if (!stack.get(stack.size() - 3).isZero() ) gasCost += GasCost.VT_CALL; callGas = callGasWord.longValue(); @@ -261,7 +260,7 @@ public class VM { * Stop and Arithmetic Operations */ case STOP: { - program.setHReturn(ByteBuffer.allocate(0)); + program.setHReturn(EMPTY_BYTE_ARRAY); program.stop(); } break; @@ -576,9 +575,9 @@ public class VM { case SHA3: { DataWord memOffsetData = program.stackPop(); DataWord lengthData = program.stackPop(); - ByteBuffer buffer = program.memoryChunk(memOffsetData, lengthData); + byte[] buffer = program.memoryChunk(memOffsetData.intValue(), lengthData.intValue()); - byte[] encoded = HashUtil.sha3(buffer.array()); + byte[] encoded = sha3(buffer); DataWord word = new DataWord(encoded); if (logger.isInfoEnabled()) @@ -702,7 +701,7 @@ public class VM { case CODECOPY: case EXTCODECOPY: { - byte[] fullCode = ByteUtil.EMPTY_BYTE_ARRAY; + byte[] fullCode = EMPTY_BYTE_ARRAY; if (op == OpCode.CODECOPY) fullCode = program.getCode(); @@ -856,10 +855,10 @@ public class VM { topics.add(topic); } - ByteBuffer data = program.memoryChunk(memStart, memOffset); + byte[] data = program.memoryChunk(memStart.intValue(), memOffset.intValue()); LogInfo logInfo = - new LogInfo(address.getLast20Bytes(), topics, data.array()); + new LogInfo(address.getLast20Bytes(), topics, data); if (logger.isInfoEnabled()) hint = logInfo.toString(); @@ -1056,7 +1055,7 @@ public class VM { DataWord codeAddress = program.stackPop(); DataWord value = program.stackPop(); - if( value.intValue() > 0) + if( !value.isZero()) gas = new DataWord(gas.intValue() + GasCost.STIPEND_CALL); DataWord inDataOffs = program.stackPop(); @@ -1100,11 +1099,11 @@ public class VM { DataWord offset = program.stackPop(); DataWord size = program.stackPop(); - ByteBuffer hReturn = program.memoryChunk(offset, size); + byte[] hReturn = program.memoryChunk(offset.intValue(), size.intValue()); program.setHReturn(hReturn); if (logger.isInfoEnabled()) - hint = "data: " + Hex.toHexString(hReturn.array()) + hint = "data: " + Hex.toHexString(hReturn) + " offset: " + offset.value() + " size: " + size.value(); diff --git a/ethereumj-core/src/main/java/org/ethereum/vmtrace/Op.java b/ethereumj-core/src/main/java/org/ethereum/vmtrace/Op.java index cd2840fa..c9fcf77a 100644 --- a/ethereumj-core/src/main/java/org/ethereum/vmtrace/Op.java +++ b/ethereumj-core/src/main/java/org/ethereum/vmtrace/Op.java @@ -66,9 +66,8 @@ public class Op { } } - public void saveMemory(ByteBuffer memory) { - if (memory != null) - this.memory = Arrays.copyOf(memory.array(), memory.array().length); + public void saveMemory(byte[] memory) { + this.memory = memory; } public void saveStack(Stack stack) { diff --git a/ethereumj-core/src/main/java/org/ethereum/wallet/EtherSaleWallet.java b/ethereumj-core/src/main/java/org/ethereum/wallet/EtherSaleWallet.java index 641fba07..885eb1e9 100644 --- a/ethereumj-core/src/main/java/org/ethereum/wallet/EtherSaleWallet.java +++ b/ethereumj-core/src/main/java/org/ethereum/wallet/EtherSaleWallet.java @@ -68,4 +68,4 @@ public class EtherSaleWallet { } return data; } -} +} \ No newline at end of file diff --git a/ethereumj-core/src/main/resources/applicationContext.xml b/ethereumj-core/src/main/resources/applicationContext.xml index 78e7f7ae..6d3e81b8 100644 --- a/ethereumj-core/src/main/resources/applicationContext.xml +++ b/ethereumj-core/src/main/resources/applicationContext.xml @@ -112,7 +112,8 @@ - + +