Merged poc-9-merge-rlpx from main repo.
This commit is contained in:
parent
22f70082c4
commit
ea2fc0239f
|
@ -45,6 +45,7 @@ public class SystemProperties {
|
||||||
private final static int DEFAULT_PEER_LISTEN_PORT = 30303;
|
private final static int DEFAULT_PEER_LISTEN_PORT = 30303;
|
||||||
private final static String DEFAULT_KEY_VALUE_DATA_SOURCE = "leveldb";
|
private final static String DEFAULT_KEY_VALUE_DATA_SOURCE = "leveldb";
|
||||||
private final static boolean DEFAULT_REDIS_ENABLED = true;
|
private final static boolean DEFAULT_REDIS_ENABLED = true;
|
||||||
|
private static final String DEFAULT_BLOCKS_LOADER = "";
|
||||||
|
|
||||||
|
|
||||||
/* Testing */
|
/* Testing */
|
||||||
|
@ -288,6 +289,11 @@ public class SystemProperties {
|
||||||
return Boolean.parseBoolean(prop.getProperty("GitHubTests.VMTest.loadLocal", String.valueOf(DEFAULT_VMTEST_LOAD_LOCAL)));
|
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[]) {
|
public static void main(String args[]) {
|
||||||
SystemProperties systemProperties = new SystemProperties();
|
SystemProperties systemProperties = new SystemProperties();
|
||||||
systemProperties.print();
|
systemProperties.print();
|
||||||
|
|
|
@ -563,19 +563,19 @@ public class BlockchainImpl implements Blockchain {
|
||||||
public void storeBlock(Block block, List<TransactionReceipt> receipts) {
|
public void storeBlock(Block block, List<TransactionReceipt> receipts) {
|
||||||
|
|
||||||
/* Debug check to see if the state is still as expected */
|
/* Debug check to see if the state is still as expected */
|
||||||
if (logger.isWarnEnabled()) {
|
String blockStateRootHash = Hex.toHexString(block.getStateRoot());
|
||||||
String blockStateRootHash = Hex.toHexString(block.getStateRoot());
|
String worldStateRootHash = Hex.toHexString(repository.getRoot());
|
||||||
String worldStateRootHash = Hex.toHexString(repository.getRoot());
|
if (!blockStateRootHash.equals(worldStateRootHash)) {
|
||||||
if (!blockStateRootHash.equals(worldStateRootHash)) {
|
|
||||||
|
|
||||||
stateLogger.error("BLOCK: STATE CONFLICT! block: {} worldstate {} mismatch", block.getNumber(), worldStateRootHash);
|
stateLogger.error("BLOCK: STATE CONFLICT! block: {} worldstate {} mismatch", block.getNumber(), worldStateRootHash);
|
||||||
adminInfo.lostConsensus();
|
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());
|
// Block parentBlock = blockStore.getBlockByHash(block.getParentHash());
|
||||||
// repository.syncToRoot(parentBlock.getStateRoot());
|
// 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);
|
blockStore.saveBlock(block, receipts);
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package org.ethereum.core;
|
package org.ethereum.core;
|
||||||
|
|
||||||
|
//import jdk.jfr.events.ThrowablesEvent;
|
||||||
import org.ethereum.db.BlockStore;
|
import org.ethereum.db.BlockStore;
|
||||||
import org.ethereum.facade.Repository;
|
import org.ethereum.facade.Repository;
|
||||||
import org.ethereum.listener.EthereumListener;
|
import org.ethereum.listener.EthereumListener;
|
||||||
|
@ -181,13 +182,18 @@ public class TransactionExecutor {
|
||||||
private void create() {
|
private void create() {
|
||||||
|
|
||||||
byte[] newContractAddress = tx.getContractAddress();
|
byte[] newContractAddress = tx.getContractAddress();
|
||||||
if (!(tx.getData().length == 0)){
|
if (tx.getData() != null && !(tx.getData().length == 0)){
|
||||||
|
|
||||||
ProgramInvoke programInvoke =
|
ProgramInvoke programInvoke =
|
||||||
programInvokeFactory.createProgramInvoke(tx, currentBlock, cacheTrack, blockStore);
|
programInvokeFactory.createProgramInvoke(tx, currentBlock, cacheTrack, blockStore);
|
||||||
|
|
||||||
this.vm = new VM();
|
this.vm = new VM();
|
||||||
this.program = new Program(tx.getData(), programInvoke);
|
this.program = new Program(tx.getData(), programInvoke);
|
||||||
|
} else {
|
||||||
|
|
||||||
|
|
||||||
|
m_endGas = toBI(tx.getGasLimit()).longValue() - basicTxCost;
|
||||||
|
cacheTrack.createAccount(tx.getContractAddress());
|
||||||
}
|
}
|
||||||
|
|
||||||
BigInteger endowment = toBI(tx.getValue());
|
BigInteger endowment = toBI(tx.getValue());
|
||||||
|
|
|
@ -368,4 +368,4 @@ public class Wallet {
|
||||||
public void setHigh(long high) {
|
public void setHigh(long high) {
|
||||||
this.high = high;
|
this.high = high;
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -29,7 +29,7 @@ public class RedisConnectionImpl implements RedisConnection {
|
||||||
if (!SystemProperties.CONFIG.isRedisEnabled()) return;
|
if (!SystemProperties.CONFIG.isRedisEnabled()) return;
|
||||||
|
|
||||||
String redisCloudUrl = System.getenv(REDISCLOUD_URL);
|
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.");
|
logger.info("Cannot connect to Redis. 'REDISCLOUD_URL' environment variable is not defined.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,37 +17,27 @@ public interface BlockStore {
|
||||||
|
|
||||||
public byte[] getBlockHashByNumber(long blockNumber);
|
public byte[] getBlockHashByNumber(long blockNumber);
|
||||||
|
|
||||||
//@Transactional(readOnly = true)
|
|
||||||
Block getBlockByNumber(long blockNumber);
|
Block getBlockByNumber(long blockNumber);
|
||||||
|
|
||||||
//@Transactional(readOnly = true)
|
|
||||||
Block getBlockByHash(byte[] hash);
|
Block getBlockByHash(byte[] hash);
|
||||||
|
|
||||||
//@Transactional(readOnly = true)
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
List<byte[]> getListOfHashesStartFrom(byte[] hash, int qty);
|
List<byte[]> getListOfHashesStartFrom(byte[] hash, int qty);
|
||||||
|
|
||||||
//@Transactional
|
|
||||||
void deleteBlocksSince(long number);
|
void deleteBlocksSince(long number);
|
||||||
|
|
||||||
//@Transactional
|
|
||||||
void saveBlock(Block block, List<TransactionReceipt> receipts);
|
void saveBlock(Block block, List<TransactionReceipt> receipts);
|
||||||
|
|
||||||
//@Transactional(readOnly = true)
|
|
||||||
BigInteger getTotalDifficultySince(long number);
|
BigInteger getTotalDifficultySince(long number);
|
||||||
|
|
||||||
//@Transactional(readOnly = true)
|
|
||||||
BigInteger getTotalDifficulty();
|
BigInteger getTotalDifficulty();
|
||||||
|
|
||||||
//@Transactional(readOnly = true)
|
|
||||||
Block getBestBlock();
|
Block getBestBlock();
|
||||||
|
|
||||||
//@Transactional(readOnly = true)
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
List<Block> getAllBlocks();
|
List<Block> getAllBlocks();
|
||||||
|
|
||||||
//@Transactional
|
|
||||||
void reset();
|
void reset();
|
||||||
|
|
||||||
TransactionReceipt getTransactionReceiptByHash(byte[] hash);
|
TransactionReceipt getTransactionReceiptByHash(byte[] hash);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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<byte[]> getListOfHashesStartFrom(byte[] hash, int qty) {
|
||||||
|
|
||||||
|
List<byte[]> hashes = new ArrayList<>();
|
||||||
|
|
||||||
|
// find block number of that block hash
|
||||||
|
Block block = getBlockByHash(hash);
|
||||||
|
if (block == null) return hashes;
|
||||||
|
|
||||||
|
List<byte[]> 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<TransactionReceipt> 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<Block> getAllBlocks() {
|
||||||
|
|
||||||
|
List<BlockVO> result = sessionFactory.getCurrentSession().
|
||||||
|
createQuery("from BlockVO").list();
|
||||||
|
|
||||||
|
ArrayList<Block> 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);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -301,4 +301,4 @@ public class RepositoryDummy extends RepositoryImpl {
|
||||||
cacheAccounts.put(wrap(addr), account);
|
cacheAccounts.put(wrap(addr), account);
|
||||||
cacheDetails.put(wrap(addr), details);
|
cacheDetails.put(wrap(addr), details);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -486,4 +486,4 @@ public class RepositoryImpl implements Repository {
|
||||||
public byte[] getRoot() {
|
public byte[] getRoot() {
|
||||||
return worldState.getRootHash();
|
return worldState.getRootHash();
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -287,4 +287,4 @@ public class RepositoryTrack implements Repository {
|
||||||
throw new UnsupportedOperationException();
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -302,4 +302,4 @@ public class RepositoryVMTestDummy extends RepositoryImpl{
|
||||||
cacheAccounts.put(wrap(addr), account);
|
cacheAccounts.put(wrap(addr), account);
|
||||||
cacheDetails.put(wrap(addr), details);
|
cacheDetails.put(wrap(addr), details);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -4,16 +4,14 @@ import org.ethereum.core.Transaction;
|
||||||
import org.ethereum.core.Wallet;
|
import org.ethereum.core.Wallet;
|
||||||
import org.ethereum.listener.EthereumListener;
|
import org.ethereum.listener.EthereumListener;
|
||||||
import org.ethereum.manager.AdminInfo;
|
import org.ethereum.manager.AdminInfo;
|
||||||
|
import org.ethereum.manager.BlockLoader;
|
||||||
import org.ethereum.net.client.PeerClient;
|
import org.ethereum.net.client.PeerClient;
|
||||||
import org.ethereum.net.peerdiscovery.PeerInfo;
|
import org.ethereum.net.peerdiscovery.PeerInfo;
|
||||||
import org.ethereum.net.rlpx.FrameCodec;
|
|
||||||
import org.ethereum.net.server.ChannelManager;
|
import org.ethereum.net.server.ChannelManager;
|
||||||
import org.springframework.context.ApplicationContext;
|
import org.springframework.context.ApplicationContext;
|
||||||
|
|
||||||
import java.math.BigInteger;
|
import java.math.BigInteger;
|
||||||
|
|
||||||
import java.net.InetAddress;
|
import java.net.InetAddress;
|
||||||
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.Future;
|
import java.util.concurrent.Future;
|
||||||
|
|
||||||
|
@ -139,5 +137,5 @@ public interface Ethereum {
|
||||||
|
|
||||||
public Set<Transaction> getPendingTransactions();
|
public Set<Transaction> getPendingTransactions();
|
||||||
|
|
||||||
|
public BlockLoader getBlockLoader();
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,4 +33,4 @@ public class EthereumFactory {
|
||||||
return context.getBean(Ethereum.class);
|
return context.getBean(Ethereum.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -4,10 +4,10 @@ import org.ethereum.core.Transaction;
|
||||||
import org.ethereum.core.Wallet;
|
import org.ethereum.core.Wallet;
|
||||||
import org.ethereum.listener.EthereumListener;
|
import org.ethereum.listener.EthereumListener;
|
||||||
import org.ethereum.manager.AdminInfo;
|
import org.ethereum.manager.AdminInfo;
|
||||||
|
import org.ethereum.manager.BlockLoader;
|
||||||
import org.ethereum.manager.WorldManager;
|
import org.ethereum.manager.WorldManager;
|
||||||
import org.ethereum.net.client.PeerClient;
|
import org.ethereum.net.client.PeerClient;
|
||||||
import org.ethereum.net.peerdiscovery.PeerInfo;
|
import org.ethereum.net.peerdiscovery.PeerInfo;
|
||||||
import org.ethereum.net.rlpx.FrameCodec;
|
|
||||||
import org.ethereum.net.server.ChannelManager;
|
import org.ethereum.net.server.ChannelManager;
|
||||||
import org.ethereum.net.server.PeerServer;
|
import org.ethereum.net.server.PeerServer;
|
||||||
import org.ethereum.net.submit.TransactionExecutor;
|
import org.ethereum.net.submit.TransactionExecutor;
|
||||||
|
@ -55,6 +55,9 @@ public class EthereumImpl implements Ethereum {
|
||||||
@Autowired
|
@Autowired
|
||||||
ApplicationContext ctx;
|
ApplicationContext ctx;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
BlockLoader blockLoader;
|
||||||
|
|
||||||
public EthereumImpl() {
|
public EthereumImpl() {
|
||||||
System.out.println();
|
System.out.println();
|
||||||
logger.info("EthereumImpl constructor");
|
logger.info("EthereumImpl constructor");
|
||||||
|
@ -253,5 +256,8 @@ public class EthereumImpl implements Ethereum {
|
||||||
return getBlockchain().getPendingTransactions();
|
return getBlockchain().getPendingTransactions();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockLoader getBlockLoader(){
|
||||||
|
return blockLoader;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -134,4 +134,4 @@ public class JSONReader {
|
||||||
|
|
||||||
return fileNames;
|
return fileNames;
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -92,4 +92,4 @@ public class StateTestRunner {
|
||||||
logger.info("\n\n");
|
logger.info("\n\n");
|
||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -94,4 +94,4 @@ public class CompositeEthereumListener implements EthereumListener {
|
||||||
listeners.add(listener);
|
listeners.add(listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -56,4 +56,4 @@ public class AdminInfo {
|
||||||
public List<Long> getBlockExecTime(){
|
public List<Long> getBlockExecTime(){
|
||||||
return blockExecTime;
|
return blockExecTime;
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -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<String> 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();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -212,4 +212,4 @@ public class WorldManager {
|
||||||
repository.close();
|
repository.close();
|
||||||
blockchain.close();
|
blockchain.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -281,4 +281,4 @@ public class BlockQueue {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
|
@ -132,4 +132,4 @@ public class MessageQueue {
|
||||||
timer.cancel();
|
timer.cancel();
|
||||||
timer.purge();
|
timer.purge();
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -54,6 +54,7 @@ public class PeerClient {
|
||||||
worldManager.getListener().trace("Connecting to: " + host + ":" + port);
|
worldManager.getListener().trace("Connecting to: " + host + ":" + port);
|
||||||
|
|
||||||
EthereumChannelInitializer ethereumChannelInitializer = (EthereumChannelInitializer)ctx.getBean("ethereumChannelInitializer", EthereumChannelInitializer.class);
|
EthereumChannelInitializer ethereumChannelInitializer = (EthereumChannelInitializer)ctx.getBean("ethereumChannelInitializer", EthereumChannelInitializer.class);
|
||||||
|
ethereumChannelInitializer.setRemoteId(remoteId);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Bootstrap b = new Bootstrap();
|
Bootstrap b = new Bootstrap();
|
||||||
|
|
|
@ -139,4 +139,4 @@ public class DiscoveryChannel {
|
||||||
public StatusMessage getStatusHandshake() {
|
public StatusMessage getStatusHandshake() {
|
||||||
return ethHandler.getHandshakeStatusMessage();
|
return ethHandler.getHandshakeStatusMessage();
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -85,4 +85,4 @@ public class WorkerThread implements Runnable {
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "Worker for: " + this.peerInfo.toString();
|
return "Worker for: " + this.peerInfo.toString();
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -157,4 +157,4 @@ public class Channel {
|
||||||
public void setInetSocketAddress(InetSocketAddress inetSocketAddress) {
|
public void setInetSocketAddress(InetSocketAddress inetSocketAddress) {
|
||||||
this.inetSocketAddress = inetSocketAddress;
|
this.inetSocketAddress = inetSocketAddress;
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -141,4 +141,4 @@ public class ChannelManager {
|
||||||
public List<Channel> getChannels() {
|
public List<Channel> getChannels() {
|
||||||
return channels;
|
return channels;
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -79,4 +79,8 @@ public class EthereumChannelInitializer extends ChannelInitializer<NioSocketChan
|
||||||
ch.config().setOption(ChannelOption.SO_BACKLOG, 1024);
|
ch.config().setOption(ChannelOption.SO_BACKLOG, 1024);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
public void setRemoteId(String remoteId) {
|
||||||
|
this.remoteId = remoteId;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -84,4 +84,4 @@ public class PeerServer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -19,4 +19,4 @@ public class AdvancedDeviceUtils {
|
||||||
//PropertyConfigurator.configure(configFile);
|
//PropertyConfigurator.configure(configFile);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -405,7 +405,11 @@ public class ByteUtil {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isNullOrZeroArray(byte[] array){
|
public static boolean isNullOrZeroArray(byte[] array){
|
||||||
return (array == null) || (array.length == 0) || (array.length == 1 && array[0] == 0);
|
return (array == null) || (array.length == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isSingleZero(byte[] array){
|
||||||
|
return (array.length == 1 && array[0] == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@ import java.util.*;
|
||||||
import static java.util.Arrays.copyOfRange;
|
import static java.util.Arrays.copyOfRange;
|
||||||
import static org.ethereum.util.ByteUtil.byteArrayToInt;
|
import static org.ethereum.util.ByteUtil.byteArrayToInt;
|
||||||
import static org.ethereum.util.ByteUtil.isNullOrZeroArray;
|
import static org.ethereum.util.ByteUtil.isNullOrZeroArray;
|
||||||
|
import static org.ethereum.util.ByteUtil.isSingleZero;
|
||||||
import static org.spongycastle.util.Arrays.concatenate;
|
import static org.spongycastle.util.Arrays.concatenate;
|
||||||
import static org.spongycastle.util.BigIntegers.asUnsignedByteArray;
|
import static org.spongycastle.util.BigIntegers.asUnsignedByteArray;
|
||||||
|
|
||||||
|
@ -748,6 +749,8 @@ public class RLP {
|
||||||
|
|
||||||
if (isNullOrZeroArray(srcData))
|
if (isNullOrZeroArray(srcData))
|
||||||
return new byte[]{(byte) OFFSET_SHORT_ITEM};
|
return new byte[]{(byte) OFFSET_SHORT_ITEM};
|
||||||
|
else if(isSingleZero(srcData))
|
||||||
|
return new byte[]{00};
|
||||||
else if (srcData.length == 1 && (srcData[0] & 0xFF) < 0x80) {
|
else if (srcData.length == 1 && (srcData[0] & 0xFF) < 0x80) {
|
||||||
return srcData;
|
return srcData;
|
||||||
} else if (srcData.length < SIZE_THRESHOLD) {
|
} else if (srcData.length < SIZE_THRESHOLD) {
|
||||||
|
|
|
@ -134,4 +134,4 @@ public class Utils {
|
||||||
return sb.append(" ").append(firstHash).append("...").append(lastHash).toString();
|
return sb.append(" ").append(firstHash).append("...").append(lastHash).toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -53,6 +53,8 @@ public class DataWord implements Comparable<DataWord> {
|
||||||
public DataWord(byte[] data) {
|
public DataWord(byte[] data) {
|
||||||
if (data == null)
|
if (data == null)
|
||||||
this.data = ByteUtil.EMPTY_BYTE_ARRAY;
|
this.data = ByteUtil.EMPTY_BYTE_ARRAY;
|
||||||
|
else if (data.length == 32)
|
||||||
|
this.data = data;
|
||||||
else if (data.length <= 32)
|
else if (data.length <= 32)
|
||||||
System.arraycopy(data, 0, this.data, 32 - data.length, data.length);
|
System.arraycopy(data, 0, this.data, 32 - data.length, data.length);
|
||||||
else
|
else
|
||||||
|
@ -84,10 +86,14 @@ public class DataWord implements Comparable<DataWord> {
|
||||||
* @throws ArithmeticException - if this will not fit in an int.
|
* @throws ArithmeticException - if this will not fit in an int.
|
||||||
*/
|
*/
|
||||||
public int intValue() {
|
public int intValue() {
|
||||||
BigDecimal tmpValue = new BigDecimal(this.value());
|
int intVal = 0;
|
||||||
if (this.bytesOccupied() > 4)
|
|
||||||
return Integer.MAX_VALUE;
|
for (int i = 0; i < data.length; i++)
|
||||||
return tmpValue.intValueExact();
|
{
|
||||||
|
intVal = (intVal << 8) + (data[i] & 0xff);
|
||||||
|
}
|
||||||
|
|
||||||
|
return intVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -99,10 +105,17 @@ public class DataWord implements Comparable<DataWord> {
|
||||||
* @throws ArithmeticException - if this will not fit in a long.
|
* @throws ArithmeticException - if this will not fit in a long.
|
||||||
*/
|
*/
|
||||||
public long longValue() {
|
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() {
|
public BigInteger sValue() {
|
||||||
return new BigInteger(data);
|
return new BigInteger(data);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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<byte[]> chunks = new LinkedList<byte[]>();
|
||||||
|
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]);
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,7 +3,6 @@ package org.ethereum.vm;
|
||||||
import org.ethereum.crypto.HashUtil;
|
import org.ethereum.crypto.HashUtil;
|
||||||
import org.ethereum.db.ContractDetails;
|
import org.ethereum.db.ContractDetails;
|
||||||
import org.ethereum.facade.Repository;
|
import org.ethereum.facade.Repository;
|
||||||
import org.ethereum.util.BIUtil;
|
|
||||||
import org.ethereum.util.ByteUtil;
|
import org.ethereum.util.ByteUtil;
|
||||||
import org.ethereum.vm.MessageCall.MsgType;
|
import org.ethereum.vm.MessageCall.MsgType;
|
||||||
import org.ethereum.vm.PrecompiledContracts.PrecompiledContract;
|
import org.ethereum.vm.PrecompiledContracts.PrecompiledContract;
|
||||||
|
@ -54,7 +53,7 @@ public class Program {
|
||||||
private ProgramListener listener;
|
private ProgramListener listener;
|
||||||
|
|
||||||
Stack<DataWord> stack = new Stack<>();
|
Stack<DataWord> stack = new Stack<>();
|
||||||
ByteBuffer memory = null;
|
MemoryBuffer memory = new MemoryBuffer();
|
||||||
DataWord programAddress;
|
DataWord programAddress;
|
||||||
|
|
||||||
ProgramResult result = new ProgramResult();
|
ProgramResult result = new ProgramResult();
|
||||||
|
@ -164,8 +163,8 @@ public class Program {
|
||||||
stopped = true;
|
stopped = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setHReturn(ByteBuffer buff) {
|
public void setHReturn(byte[] buff) {
|
||||||
result.setHReturn(buff.array());
|
result.setHReturn(buff);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void step() {
|
public void step() {
|
||||||
|
@ -209,15 +208,15 @@ public class Program {
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getMemSize() {
|
public int getMemSize() {
|
||||||
return memory != null ? memory.limit() : 0;
|
return memory.getSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void memorySave(DataWord addrB, DataWord value) {
|
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) {
|
public void memorySave(int addr, byte[] value) {
|
||||||
memorySave(addr, value.length, value);
|
memory.memorySave(addr, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void memoryExpand(DataWord outDataOffs, DataWord outDataSize) {
|
public void memoryExpand(DataWord outDataOffs, DataWord outDataSize) {
|
||||||
|
@ -225,10 +224,7 @@ public class Program {
|
||||||
if (outDataSize.isZero())
|
if (outDataSize.isZero())
|
||||||
return ;
|
return ;
|
||||||
|
|
||||||
int maxAddress = outDataOffs.intValue() + outDataSize.intValue();
|
memory.memoryExpand(outDataOffs.intValue(), outDataSize.intValue());
|
||||||
if (getMemSize() < maxAddress) {
|
|
||||||
memorySave(maxAddress, new byte[]{0});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -239,47 +235,20 @@ public class Program {
|
||||||
* @param value the data to write to memory
|
* @param value the data to write to memory
|
||||||
*/
|
*/
|
||||||
public void memorySave(int addr, int allocSize, byte[] value) {
|
public void memorySave(int addr, int allocSize, byte[] value) {
|
||||||
|
memory.memorySave(addr, allocSize, value);
|
||||||
allocateMemory(addr, allocSize);
|
|
||||||
System.arraycopy(value, 0, memory.array(), addr, value.length);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public DataWord memoryLoad(DataWord addr) {
|
public DataWord memoryLoad(DataWord addr) {
|
||||||
return memoryLoad(addr.intValue());
|
return memory.memoryLoad(addr.intValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
public DataWord memoryLoad(int address) {
|
public DataWord memoryLoad(int address) {
|
||||||
|
|
||||||
allocateMemory(address, DataWord.ZERO.getData().length);
|
return memory.memoryLoad(address);
|
||||||
|
|
||||||
DataWord newMem = new DataWord();
|
|
||||||
System.arraycopy(memory.array(), address, newMem.getData(), 0, newMem.getData().length);
|
|
||||||
|
|
||||||
return newMem;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public ByteBuffer memoryChunk(DataWord offsetData, DataWord sizeData) {
|
public byte[] memoryChunk(int offset, int size) {
|
||||||
return memoryChunk(offsetData.intValue(), sizeData.intValue());
|
return memory.memoryChunk(offset, size);
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -290,14 +259,7 @@ public class Program {
|
||||||
* @param size the number of bytes to allocate
|
* @param size the number of bytes to allocate
|
||||||
*/
|
*/
|
||||||
public void allocateMemory(int offset, int size) {
|
public void allocateMemory(int offset, int size) {
|
||||||
|
memory.memoryExpand(offset, 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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -332,7 +294,7 @@ public class Program {
|
||||||
}
|
}
|
||||||
|
|
||||||
// [1] FETCH THE CODE FROM THE MEMORY
|
// [1] FETCH THE CODE FROM THE MEMORY
|
||||||
byte[] programCode = memoryChunk(memStart, memSize).array();
|
byte[] programCode = memoryChunk(memStart.intValue(), memSize.intValue());
|
||||||
|
|
||||||
if (logger.isInfoEnabled())
|
if (logger.isInfoEnabled())
|
||||||
logger.info("creating a new contract inside contract run: [{}]", Hex.toHexString(senderAddress));
|
logger.info("creating a new contract inside contract run: [{}]", Hex.toHexString(senderAddress));
|
||||||
|
@ -453,7 +415,7 @@ public class Program {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
byte[] data = memoryChunk(msg.getInDataOffs(), msg.getInDataSize()).array();
|
byte[] data = memoryChunk(msg.getInDataOffs().intValue(), msg.getInDataSize().intValue());
|
||||||
|
|
||||||
// FETCH THE SAVED STORAGE
|
// FETCH THE SAVED STORAGE
|
||||||
byte[] codeAddress = msg.getCodeAddress().getLast20Bytes();
|
byte[] codeAddress = msg.getCodeAddress().getLast20Bytes();
|
||||||
|
@ -550,7 +512,7 @@ public class Program {
|
||||||
refundGas.toString());
|
refundGas.toString());
|
||||||
}
|
}
|
||||||
} else {
|
} 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() {
|
public String memoryToString() {
|
||||||
StringBuilder memoryData = new StringBuilder();
|
return memory.memoryToString();
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void fullTrace() {
|
public void fullTrace() {
|
||||||
|
@ -737,6 +678,7 @@ public class Program {
|
||||||
stackData.append(" ").append(stack.get(i));
|
stackData.append(" ").append(stack.get(i));
|
||||||
if (i < stack.size() - 1) stackData.append("\n");
|
if (i < stack.size() - 1) stackData.append("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (stackData.length() > 0) stackData.insert(0, "\n");
|
if (stackData.length() > 0) stackData.insert(0, "\n");
|
||||||
|
|
||||||
ContractDetails contractDetails = this.result.getRepository().
|
ContractDetails contractDetails = this.result.getRepository().
|
||||||
|
@ -754,20 +696,26 @@ public class Program {
|
||||||
|
|
||||||
StringBuilder memoryData = new StringBuilder();
|
StringBuilder memoryData = new StringBuilder();
|
||||||
StringBuilder oneLine = 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);
|
byte value = memory.getByte(i);
|
||||||
oneLine.append(ByteUtil.oneByteToHexString(value)).append(" ");
|
oneLine.append(ByteUtil.oneByteToHexString(value)).append(" ");
|
||||||
|
|
||||||
if ((i + 1) % 16 == 0) {
|
if ((i + 1) % 16 == 0) {
|
||||||
String tmp = format("[%4s]-[%4s]", Integer.toString(i - 15, 16),
|
String tmp = format("[%4s]-[%4s]", Integer.toString(i - 15, 16),
|
||||||
Integer.toString(i, 16)).replace(" ", "0");
|
Integer.toString(i, 16)).replace(" ", "0");
|
||||||
memoryData.append("").append(tmp).append(" ");
|
memoryData.append("").append(tmp).append(" ");
|
||||||
memoryData.append(oneLine);
|
memoryData.append(oneLine);
|
||||||
if (i < memory.limit()) memoryData.append("\n");
|
if (i < memory.getSize()) memoryData.append("\n");
|
||||||
oneLine.setLength(0);
|
oneLine.setLength(0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if (memoryData.length() > 0) memoryData.insert(0, "\n");
|
if (memoryData.length() > 0) memoryData.insert(0, "\n");
|
||||||
|
|
||||||
StringBuilder opsString = new StringBuilder();
|
StringBuilder opsString = new StringBuilder();
|
||||||
|
@ -834,7 +782,7 @@ public class Program {
|
||||||
ContractDetails contractDetails = this.result.getRepository().
|
ContractDetails contractDetails = this.result.getRepository().
|
||||||
getContractDetails(this.programAddress.getLast20Bytes());
|
getContractDetails(this.programAddress.getLast20Bytes());
|
||||||
op.saveStorageMap(contractDetails.getStorage());
|
op.saveStorageMap(contractDetails.getStorage());
|
||||||
op.saveMemory(memory);
|
op.saveMemory(memory.memoryChunk(0, memory.getSize()));
|
||||||
op.saveStack(stack);
|
op.saveStack(stack);
|
||||||
|
|
||||||
programTrace.addOp(op);
|
programTrace.addOp(op);
|
||||||
|
@ -842,7 +790,7 @@ public class Program {
|
||||||
|
|
||||||
public void saveProgramTraceToFile(String fileName) {
|
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() + "/";
|
String dir = CONFIG.databaseDir() + "/" + CONFIG.vmTraceDir() + "/";
|
||||||
|
|
||||||
|
@ -949,7 +897,8 @@ public class Program {
|
||||||
return;
|
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());
|
transfer(track, senderAddress, codeAddress, msg.getEndowment().value());
|
||||||
|
|
||||||
|
@ -1062,15 +1011,15 @@ public class Program {
|
||||||
/**
|
/**
|
||||||
* used mostly for testing reasons
|
* used mostly for testing reasons
|
||||||
*/
|
*/
|
||||||
public ByteBuffer getMemory() {
|
public byte[] getMemory() {
|
||||||
return memory;
|
return memory.memoryChunk(0, memory.getSize());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* used mostly for testing reasons
|
* used mostly for testing reasons
|
||||||
*/
|
*/
|
||||||
public void initMem(ByteBuffer memory) {
|
public void initMem(byte[] data) {
|
||||||
this.memory = memory;
|
this.memory.memorySave(0, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -189,4 +189,4 @@ public class ProgramInvokeFactoryImpl implements ProgramInvokeFactory {
|
||||||
public void setBlockchain(Blockchain blockchain) {
|
public void setBlockchain(Blockchain blockchain) {
|
||||||
this.blockchain = blockchain;
|
this.blockchain = blockchain;
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,21 +1,20 @@
|
||||||
package org.ethereum.vm;
|
package org.ethereum.vm;
|
||||||
|
|
||||||
import org.ethereum.crypto.HashUtil;
|
|
||||||
import org.ethereum.db.ContractDetails;
|
import org.ethereum.db.ContractDetails;
|
||||||
import org.ethereum.util.ByteUtil;
|
|
||||||
import org.ethereum.vm.MessageCall.MsgType;
|
import org.ethereum.vm.MessageCall.MsgType;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.spongycastle.util.encoders.Hex;
|
import org.spongycastle.util.encoders.Hex;
|
||||||
|
|
||||||
import java.math.BigInteger;
|
import java.math.BigInteger;
|
||||||
import java.nio.ByteBuffer;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Stack;
|
import java.util.Stack;
|
||||||
|
|
||||||
import static org.ethereum.config.SystemProperties.CONFIG;
|
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.*;
|
import static org.ethereum.vm.OpCode.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -183,7 +182,7 @@ public class VM {
|
||||||
gasCost += GasCost.NEW_ACCT_CALL;
|
gasCost += GasCost.NEW_ACCT_CALL;
|
||||||
|
|
||||||
//TODO #POC9 Make sure this is converted to BigInteger (256num support)
|
//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;
|
gasCost += GasCost.VT_CALL;
|
||||||
|
|
||||||
callGas = callGasWord.longValue();
|
callGas = callGasWord.longValue();
|
||||||
|
@ -261,7 +260,7 @@ public class VM {
|
||||||
* Stop and Arithmetic Operations
|
* Stop and Arithmetic Operations
|
||||||
*/
|
*/
|
||||||
case STOP: {
|
case STOP: {
|
||||||
program.setHReturn(ByteBuffer.allocate(0));
|
program.setHReturn(EMPTY_BYTE_ARRAY);
|
||||||
program.stop();
|
program.stop();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -576,9 +575,9 @@ public class VM {
|
||||||
case SHA3: {
|
case SHA3: {
|
||||||
DataWord memOffsetData = program.stackPop();
|
DataWord memOffsetData = program.stackPop();
|
||||||
DataWord lengthData = 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);
|
DataWord word = new DataWord(encoded);
|
||||||
|
|
||||||
if (logger.isInfoEnabled())
|
if (logger.isInfoEnabled())
|
||||||
|
@ -702,7 +701,7 @@ public class VM {
|
||||||
case CODECOPY:
|
case CODECOPY:
|
||||||
case EXTCODECOPY: {
|
case EXTCODECOPY: {
|
||||||
|
|
||||||
byte[] fullCode = ByteUtil.EMPTY_BYTE_ARRAY;
|
byte[] fullCode = EMPTY_BYTE_ARRAY;
|
||||||
if (op == OpCode.CODECOPY)
|
if (op == OpCode.CODECOPY)
|
||||||
fullCode = program.getCode();
|
fullCode = program.getCode();
|
||||||
|
|
||||||
|
@ -856,10 +855,10 @@ public class VM {
|
||||||
topics.add(topic);
|
topics.add(topic);
|
||||||
}
|
}
|
||||||
|
|
||||||
ByteBuffer data = program.memoryChunk(memStart, memOffset);
|
byte[] data = program.memoryChunk(memStart.intValue(), memOffset.intValue());
|
||||||
|
|
||||||
LogInfo logInfo =
|
LogInfo logInfo =
|
||||||
new LogInfo(address.getLast20Bytes(), topics, data.array());
|
new LogInfo(address.getLast20Bytes(), topics, data);
|
||||||
|
|
||||||
if (logger.isInfoEnabled())
|
if (logger.isInfoEnabled())
|
||||||
hint = logInfo.toString();
|
hint = logInfo.toString();
|
||||||
|
@ -1056,7 +1055,7 @@ public class VM {
|
||||||
DataWord codeAddress = program.stackPop();
|
DataWord codeAddress = program.stackPop();
|
||||||
DataWord value = program.stackPop();
|
DataWord value = program.stackPop();
|
||||||
|
|
||||||
if( value.intValue() > 0)
|
if( !value.isZero())
|
||||||
gas = new DataWord(gas.intValue() + GasCost.STIPEND_CALL);
|
gas = new DataWord(gas.intValue() + GasCost.STIPEND_CALL);
|
||||||
|
|
||||||
DataWord inDataOffs = program.stackPop();
|
DataWord inDataOffs = program.stackPop();
|
||||||
|
@ -1100,11 +1099,11 @@ public class VM {
|
||||||
DataWord offset = program.stackPop();
|
DataWord offset = program.stackPop();
|
||||||
DataWord size = program.stackPop();
|
DataWord size = program.stackPop();
|
||||||
|
|
||||||
ByteBuffer hReturn = program.memoryChunk(offset, size);
|
byte[] hReturn = program.memoryChunk(offset.intValue(), size.intValue());
|
||||||
program.setHReturn(hReturn);
|
program.setHReturn(hReturn);
|
||||||
|
|
||||||
if (logger.isInfoEnabled())
|
if (logger.isInfoEnabled())
|
||||||
hint = "data: " + Hex.toHexString(hReturn.array())
|
hint = "data: " + Hex.toHexString(hReturn)
|
||||||
+ " offset: " + offset.value()
|
+ " offset: " + offset.value()
|
||||||
+ " size: " + size.value();
|
+ " size: " + size.value();
|
||||||
|
|
||||||
|
|
|
@ -66,9 +66,8 @@ public class Op {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void saveMemory(ByteBuffer memory) {
|
public void saveMemory(byte[] memory) {
|
||||||
if (memory != null)
|
this.memory = memory;
|
||||||
this.memory = Arrays.copyOf(memory.array(), memory.array().length);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void saveStack(Stack<DataWord> stack) {
|
public void saveStack(Stack<DataWord> stack) {
|
||||||
|
|
|
@ -68,4 +68,4 @@ public class EtherSaleWallet {
|
||||||
}
|
}
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -112,7 +112,8 @@
|
||||||
<bean id="listener" class="org.ethereum.listener.CompositeEthereumListener">
|
<bean id="listener" class="org.ethereum.listener.CompositeEthereumListener">
|
||||||
</bean>
|
</bean>
|
||||||
|
|
||||||
|
<bean id="blockLoader" class="org.ethereum.manager.BlockLoader">
|
||||||
|
</bean>
|
||||||
|
|
||||||
<bean id="blockStore" class="org.ethereum.db.InMemoryBlockStore">
|
<bean id="blockStore" class="org.ethereum.db.InMemoryBlockStore">
|
||||||
</bean>
|
</bean>
|
||||||
|
|
Loading…
Reference in New Issue