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 1f753772..5de85deb 100644 --- a/ethereumj-core/src/main/java/org/ethereum/core/BlockchainImpl.java +++ b/ethereumj-core/src/main/java/org/ethereum/core/BlockchainImpl.java @@ -1,6 +1,6 @@ package org.ethereum.core; -import org.ethereum.db.BlockStore; +import org.ethereum.db.BlockStoreImpl; import org.ethereum.facade.Blockchain; import org.ethereum.facade.Repository; import org.ethereum.listener.EthereumListener; @@ -79,7 +79,7 @@ public class BlockchainImpl implements Blockchain { private Repository track; @Autowired - private BlockStore blockStore; + private BlockStoreImpl blockStore; private Block bestBlock; private BigInteger totalDifficulty = BigInteger.ZERO; @@ -337,7 +337,8 @@ public class BlockchainImpl implements Blockchain { for (Transaction tx : block.getTransactionsList()) { stateLogger.info("apply block: [{}] tx: [{}] ", block.getNumber(), i); - TransactionExecutor executor = new TransactionExecutor(tx, block.getCoinbase(), track, + TransactionExecutor executor = new TransactionExecutor(tx, block.getCoinbase(), + track, blockStore, programInvokeFactory, block); executor.execute(); 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 601de85b..ebbd3370 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 org.ethereum.db.BlockStore; import org.ethereum.facade.Repository; import org.ethereum.vm.DataWord; import org.ethereum.vm.GasCost; @@ -33,6 +34,8 @@ public class TransactionExecutor { private Transaction tx; private Repository track; + private BlockStore blockStore; + private ProgramInvokeFactory programInvokeFactory; private byte[] coinbase; @@ -41,12 +44,13 @@ public class TransactionExecutor { private Block currentBlock; - public TransactionExecutor(Transaction tx, byte[] coinbase, Repository track, + public TransactionExecutor(Transaction tx, byte[] coinbase, Repository track,BlockStore blockStore, ProgramInvokeFactory programInvokeFactory, Block currentBlock) { this.tx = tx; this.coinbase = coinbase; this.track = track; + this.blockStore = blockStore; this.programInvokeFactory = programInvokeFactory; this.currentBlock = currentBlock; } @@ -180,7 +184,7 @@ public class TransactionExecutor { } ProgramInvoke programInvoke = - programInvokeFactory.createProgramInvoke(tx, currentBlock, trackTx); + programInvokeFactory.createProgramInvoke(tx, currentBlock, trackTx, blockStore); VM vm = new VM(); Program program = new Program(code, programInvoke); 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 2aff528c..9365d79f 100644 --- a/ethereumj-core/src/main/java/org/ethereum/db/BlockStore.java +++ b/ethereumj-core/src/main/java/org/ethereum/db/BlockStore.java @@ -1,179 +1,13 @@ package org.ethereum.db; import org.ethereum.core.Block; -import org.ethereum.core.TransactionReceipt; - -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 + * @author: Roman Mandeleil + * Created on: 08/01/2015 10:27 */ -@Repository -@Transactional(propagation = Propagation.SUPPORTS) -public class BlockStore { - @Autowired - private SessionFactory sessionFactory; +public interface BlockStore { - @Autowired - ApplicationContext ctx; - - - @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); - } - - @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); - } - - @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; - } - - @Transactional - public void deleteBlocksSince(long number) { - - sessionFactory.getCurrentSession(). - createQuery("delete from BlockVO where number > :number"). - setParameter("number", number). - executeUpdate(); - } - - - @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); - } - - @Transactional(readOnly = true) - public BigInteger getTotalDifficultySince(long number) { - - BigInteger result = (BigInteger) sessionFactory.getCurrentSession(). - createQuery("select sum(cummulativeDifficulty) from BlockVO where number > :number"). - setParameter("number", number). - uniqueResult(); - - return result; - } - - - @Transactional(readOnly = true) - public BigInteger getTotalDifficulty() { - - BigInteger result = (BigInteger) sessionFactory.getCurrentSession(). - createQuery("select sum(cummulativeDifficulty) from BlockVO").uniqueResult(); - - return result; - } - - - @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); - } - - @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; - } - - @Transactional - public void reset() { - sessionFactory.getCurrentSession(). - createQuery("delete from BlockVO").executeUpdate(); - } - - 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); - - } + public byte[] getBlockHashByNumber(long blockNumber); } diff --git a/ethereumj-core/src/main/java/org/ethereum/db/BlockStoreDummy.java b/ethereumj-core/src/main/java/org/ethereum/db/BlockStoreDummy.java new file mode 100644 index 00000000..2e2f4b91 --- /dev/null +++ b/ethereumj-core/src/main/java/org/ethereum/db/BlockStoreDummy.java @@ -0,0 +1,19 @@ +package org.ethereum.db; + +import org.ethereum.crypto.HashUtil; +import org.ethereum.util.ByteUtil; + +/** + * @author: Roman Mandeleil + * Created on: 08/01/2015 17:33 + */ + +public class BlockStoreDummy implements BlockStore{ + + @Override + public byte[] getBlockHashByNumber(long blockNumber) { + + byte[] data = String.valueOf(blockNumber).getBytes(); + return HashUtil.sha3(data); + } +} 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..37a2f6db --- /dev/null +++ b/ethereumj-core/src/main/java/org/ethereum/db/BlockStoreImpl.java @@ -0,0 +1,187 @@ +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 + */ +@Repository +@Transactional(propagation = Propagation.SUPPORTS) +public class BlockStoreImpl implements BlockStore{ + + @Autowired + private SessionFactory sessionFactory; + + @Autowired + ApplicationContext ctx; + + @Override + public byte[] getBlockHashByNumber(long blockNumber) { + + Block block = getBlockByNumber(blockNumber); + if (block != null) return block.getHash(); + return ByteUtil.EMPTY_BYTE_ARRAY; + } + + @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); + } + + @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); + } + + @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; + } + + @Transactional + public void deleteBlocksSince(long number) { + + sessionFactory.getCurrentSession(). + createQuery("delete from BlockVO where number > :number"). + setParameter("number", number). + executeUpdate(); + } + + + @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); + } + + @Transactional(readOnly = true) + public BigInteger getTotalDifficultySince(long number) { + + BigInteger result = (BigInteger) sessionFactory.getCurrentSession(). + createQuery("select sum(cummulativeDifficulty) from BlockVO where number > :number"). + setParameter("number", number). + uniqueResult(); + + return result; + } + + + @Transactional(readOnly = true) + public BigInteger getTotalDifficulty() { + + BigInteger result = (BigInteger) sessionFactory.getCurrentSession(). + createQuery("select sum(cummulativeDifficulty) from BlockVO").uniqueResult(); + + return result; + } + + + @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); + } + + @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; + } + + @Transactional + public void reset() { + sessionFactory.getCurrentSession(). + createQuery("delete from BlockVO").executeUpdate(); + } + + 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/jsontestsuite/TestProgramInvokeFactory.java b/ethereumj-core/src/main/java/org/ethereum/jsontestsuite/TestProgramInvokeFactory.java index 73136578..f82de1e3 100644 --- a/ethereumj-core/src/main/java/org/ethereum/jsontestsuite/TestProgramInvokeFactory.java +++ b/ethereumj-core/src/main/java/org/ethereum/jsontestsuite/TestProgramInvokeFactory.java @@ -2,6 +2,7 @@ package org.ethereum.jsontestsuite; import org.ethereum.core.Block; import org.ethereum.core.Transaction; +import org.ethereum.db.BlockStore; import org.ethereum.facade.Repository; import org.ethereum.util.ByteUtil; import org.ethereum.vm.DataWord; @@ -26,18 +27,19 @@ public class TestProgramInvokeFactory implements ProgramInvokeFactory { @Override - public ProgramInvoke createProgramInvoke(Transaction tx, Block block, Repository repository) { - return generalInvoke(tx, repository); + public ProgramInvoke createProgramInvoke(Transaction tx, Block block, Repository repository, BlockStore blockStore) { + return generalInvoke(tx, repository, blockStore); } @Override public ProgramInvoke createProgramInvoke(Program program, DataWord toAddress, DataWord inValue, DataWord inGas, - BigInteger balanceInt, byte[] dataIn, Repository repository) { + BigInteger balanceInt, byte[] dataIn, + Repository repository, BlockStore blockStore) { return null; } - private ProgramInvoke generalInvoke(Transaction tx, Repository repository) { + private ProgramInvoke generalInvoke(Transaction tx, Repository repository ,BlockStore blockStore) { /*** ADDRESS op ***/ // YP: Get address of currently executing account. @@ -88,7 +90,7 @@ public class TestProgramInvokeFactory implements ProgramInvokeFactory { return new ProgramInvokeImpl(address, origin, caller, balance, gasPrice, gas, callValue, data, lastHash, coinbase, - timestamp, number, difficulty, gaslimit, repository); + timestamp, number, difficulty, gaslimit, repository, blockStore); } } diff --git a/ethereumj-core/src/main/java/org/ethereum/jsontestsuite/TestRunner.java b/ethereumj-core/src/main/java/org/ethereum/jsontestsuite/TestRunner.java index 0ba5dcf2..2490e986 100644 --- a/ethereumj-core/src/main/java/org/ethereum/jsontestsuite/TestRunner.java +++ b/ethereumj-core/src/main/java/org/ethereum/jsontestsuite/TestRunner.java @@ -2,6 +2,7 @@ package org.ethereum.jsontestsuite; import org.ethereum.core.BlockchainImpl; import org.ethereum.core.TransactionExecutor; +import org.ethereum.db.BlockStoreDummy; import org.ethereum.db.ByteArrayWrapper; import org.ethereum.db.ContractDetails; import org.ethereum.db.RepositoryDummy; @@ -88,8 +89,9 @@ public class TestRunner { blockchain.startTracking(); Repository track = repository.startTracking(); - TransactionExecutor executor = new TransactionExecutor(tx, coinbase, track, - invokeFactory, null); + TransactionExecutor executor = + new TransactionExecutor(tx, coinbase, track, new BlockStoreDummy(), + invokeFactory, blockchain.getBestBlock()); executor.execute(); track.commit(); @@ -179,7 +181,7 @@ public class TestRunner { ProgramInvoke programInvoke = new ProgramInvokeImpl(address, origin, caller, balance, gasPrice, gas, callValue, msgData, lastHash, coinbase, - timestamp, number, difficulty, gaslimit, repository, true); + timestamp, number, difficulty, gaslimit, repository, null, true); /* 3. Create Program - exec.code */ /* 4. run VM */ 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 c85ca350..5825ba87 100644 --- a/ethereumj-core/src/main/java/org/ethereum/manager/WorldManager.java +++ b/ethereumj-core/src/main/java/org/ethereum/manager/WorldManager.java @@ -6,7 +6,7 @@ import org.ethereum.core.Transaction; import org.ethereum.core.TransactionReceipt; import org.ethereum.core.Wallet; import org.ethereum.crypto.HashUtil; -import org.ethereum.db.BlockStore; +import org.ethereum.db.BlockStoreImpl; import org.ethereum.facade.Blockchain; import org.ethereum.facade.Repository; import org.ethereum.listener.EthereumListener; @@ -63,7 +63,7 @@ public class WorldManager { private PeerDiscovery peerDiscovery; @Autowired - private BlockStore blockStore; + private BlockStoreImpl blockStore; @Autowired private ChannelManager channelManager; diff --git a/ethereumj-core/src/main/java/org/ethereum/vm/OpCode.java b/ethereumj-core/src/main/java/org/ethereum/vm/OpCode.java index ff4946eb..0f1e002f 100644 --- a/ethereumj-core/src/main/java/org/ethereum/vm/OpCode.java +++ b/ethereumj-core/src/main/java/org/ethereum/vm/OpCode.java @@ -190,7 +190,7 @@ public enum OpCode { * (0x40) Get hash of most recent * complete block */ - PREVHASH(0x40, 0), + BLOCKHASH(0x40, 1), /** * (0x41) Get the block’s coinbase address */ 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 3e550220..b81b7ed6 100644 --- a/ethereumj-core/src/main/java/org/ethereum/vm/Program.java +++ b/ethereumj-core/src/main/java/org/ethereum/vm/Program.java @@ -1,6 +1,7 @@ package org.ethereum.vm; import org.ethereum.crypto.HashUtil; +import org.ethereum.db.BlockStore; import org.ethereum.db.ContractDetails; import org.ethereum.facade.Repository; import org.ethereum.util.ByteUtil; @@ -350,7 +351,7 @@ public class Program { // [5] COOK THE INVOKE AND EXECUTE ProgramInvoke programInvoke = programInvokeFactory.createProgramInvoke( this, new DataWord(newAddress), DataWord.ZERO, gasLimit, - newBalance, null, track); + newBalance, null, track, this.invokeData.getBlockStore()); ProgramResult result = null; @@ -466,7 +467,7 @@ public class Program { Repository trackRepository = result.getRepository().startTracking(); ProgramInvoke programInvoke = programInvokeFactory.createProgramInvoke( this, new DataWord(contextAddress), msg.getEndowment(), - msg.getGas(), contextBalance, data, trackRepository); + msg.getGas(), contextBalance, data, trackRepository, this.invokeData.getBlockStore()); ProgramResult result = null; @@ -574,6 +575,22 @@ public class Program { return this.programAddress.clone(); } + public DataWord getBlockHash(int index) { + + // todo: + /// Hash of a block if within the last 256 blocks, or h256() otherwise. +// h256 blockhash(u256 _number) {return +// _number < currentBlock.number && _number >= (std::max(256, currentBlock.number) - 256) ? +// lastHashes[(unsigned)(currentBlock.number - 1 - _number)] : +// h256(); } + + return index < this.getNumber().longValue() && index >= Math.max(256, this.getNumber().intValue()) - 256? + new DataWord(this.invokeData.getBlockStore().getBlockHashByNumber(index)): + DataWord.ZERO; + + } + + public DataWord getBalance(DataWord address) { if (invokeData == null) return DataWord.ZERO_EMPTY_ARRAY; diff --git a/ethereumj-core/src/main/java/org/ethereum/vm/ProgramInvoke.java b/ethereumj-core/src/main/java/org/ethereum/vm/ProgramInvoke.java index e208d156..cf2788b6 100644 --- a/ethereumj-core/src/main/java/org/ethereum/vm/ProgramInvoke.java +++ b/ethereumj-core/src/main/java/org/ethereum/vm/ProgramInvoke.java @@ -1,5 +1,6 @@ package org.ethereum.vm; +import org.ethereum.db.BlockStore; import org.ethereum.facade.Repository; /** @@ -41,12 +42,15 @@ public interface ProgramInvoke { public DataWord getDifficulty(); public DataWord getGaslimit(); - - public Repository getRepository(); - + public boolean byTransaction(); boolean byTestingSuite(); public int getCallDeep(); + + public Repository getRepository(); + + public BlockStore getBlockStore(); + } diff --git a/ethereumj-core/src/main/java/org/ethereum/vm/ProgramInvokeFactory.java b/ethereumj-core/src/main/java/org/ethereum/vm/ProgramInvokeFactory.java index d0ec7f0b..ed4b716f 100644 --- a/ethereumj-core/src/main/java/org/ethereum/vm/ProgramInvokeFactory.java +++ b/ethereumj-core/src/main/java/org/ethereum/vm/ProgramInvokeFactory.java @@ -2,6 +2,7 @@ package org.ethereum.vm; import org.ethereum.core.Block; import org.ethereum.core.Transaction; +import org.ethereum.db.BlockStore; import org.ethereum.facade.Repository; import java.math.BigInteger; @@ -12,12 +13,13 @@ import java.math.BigInteger; */ public interface ProgramInvokeFactory { - public ProgramInvoke createProgramInvoke(Transaction tx, Block block, Repository repository); + public ProgramInvoke createProgramInvoke(Transaction tx, Block block, + Repository repository, BlockStore blockStore); public ProgramInvoke createProgramInvoke(Program program, DataWord toAddress, DataWord inValue, DataWord inGas, BigInteger balanceInt, byte[] dataIn, - Repository repository); + Repository repository, BlockStore blockStore); } 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 e6467f80..f255bee2 100644 --- a/ethereumj-core/src/main/java/org/ethereum/vm/ProgramInvokeFactoryImpl.java +++ b/ethereumj-core/src/main/java/org/ethereum/vm/ProgramInvokeFactoryImpl.java @@ -2,6 +2,8 @@ package org.ethereum.vm; import org.ethereum.core.Block; import org.ethereum.core.Transaction; +import org.ethereum.db.BlockStore; +import org.ethereum.db.BlockStoreImpl; import org.ethereum.facade.Blockchain; import org.ethereum.facade.Repository; import org.ethereum.util.ByteUtil; @@ -27,11 +29,15 @@ public class ProgramInvokeFactoryImpl implements ProgramInvokeFactory { @Autowired private Blockchain blockchain; + + @Autowired + private BlockStoreImpl blockStore; // Invocation by the wire tx @Override - public ProgramInvoke createProgramInvoke(Transaction tx, Block block, Repository repository) { + public ProgramInvoke createProgramInvoke(Transaction tx, Block block, Repository repository, + BlockStore blockStore) { // https://ethereum.etherpad.mozilla.org/26 Block lastBlock = blockchain.getBestBlock(); @@ -119,7 +125,7 @@ public class ProgramInvokeFactoryImpl implements ProgramInvokeFactory { ProgramInvoke programInvoke = new ProgramInvokeImpl(address, origin, caller, balance, gasPrice, gas, callValue, data, lastHash, coinbase, timestamp, number, difficulty, gaslimit, - repository); + repository, blockStore); return programInvoke; } @@ -131,7 +137,7 @@ public class ProgramInvokeFactoryImpl implements ProgramInvokeFactory { public ProgramInvoke createProgramInvoke(Program program, DataWord toAddress, DataWord inValue, DataWord inGas, BigInteger balanceInt, byte[] dataIn, - Repository repository) { + Repository repository, BlockStore blockStore) { DataWord address = toAddress; DataWord origin = program.getOriginAddress(); @@ -184,6 +190,6 @@ public class ProgramInvokeFactoryImpl implements ProgramInvokeFactory { return new ProgramInvokeImpl(address, origin, caller, balance, gasPrice, gas, callValue, data, lastHash, coinbase, timestamp, number, difficulty, gasLimit, - repository, program.invokeData.getCallDeep() + 1); + repository, program.invokeData.getCallDeep() + 1, blockStore); } } diff --git a/ethereumj-core/src/main/java/org/ethereum/vm/ProgramInvokeImpl.java b/ethereumj-core/src/main/java/org/ethereum/vm/ProgramInvokeImpl.java index 4cf95ac7..c133f9a3 100644 --- a/ethereumj-core/src/main/java/org/ethereum/vm/ProgramInvokeImpl.java +++ b/ethereumj-core/src/main/java/org/ethereum/vm/ProgramInvokeImpl.java @@ -1,5 +1,6 @@ package org.ethereum.vm; +import org.ethereum.db.BlockStore; import org.ethereum.facade.Repository; import java.math.BigInteger; @@ -13,6 +14,7 @@ import java.util.Map; */ public class ProgramInvokeImpl implements ProgramInvoke { + private BlockStore blockStore; /** * TRANSACTION env ** */ @@ -39,7 +41,7 @@ public class ProgramInvokeImpl implements ProgramInvoke { DataWord gasPrice, DataWord gas, DataWord callValue, byte[] msgData, DataWord lastHash, DataWord coinbase, DataWord timestamp, DataWord number, DataWord difficulty, - DataWord gaslimit, Repository repository, int callDeep) { + DataWord gaslimit, Repository repository, int callDeep, BlockStore blockStore) { // Transaction env this.address = address; @@ -62,15 +64,16 @@ public class ProgramInvokeImpl implements ProgramInvoke { this.repository = repository; this.byTransaction = false; this.callDeep = callDeep; + this.blockStore = blockStore; } public ProgramInvokeImpl(byte[] address, byte[] origin, byte[] caller, byte[] balance, byte[] gasPrice, byte[] gas, byte[] callValue, byte[] msgData, byte[] lastHash, byte[] coinbase, long timestamp, long number, byte[] difficulty, long gaslimit, - Repository repository, boolean byTestingSuite) { + Repository repository, BlockStore blockStore,boolean byTestingSuite) { this(address, origin, caller, balance, gasPrice, gas, callValue, msgData, lastHash, coinbase, - timestamp, number, difficulty, gaslimit, repository); + timestamp, number, difficulty, gaslimit, repository, blockStore); this.byTestingSuite = byTestingSuite; } @@ -79,7 +82,7 @@ public class ProgramInvokeImpl implements ProgramInvoke { byte[] gasPrice, byte[] gas, byte[] callValue, byte[] msgData, byte[] lastHash, byte[] coinbase, long timestamp, long number, byte[] difficulty, long gaslimit, - Repository repository) { + Repository repository, BlockStore blockStore) { // Transaction env this.address = new DataWord(address); @@ -100,6 +103,7 @@ public class ProgramInvokeImpl implements ProgramInvoke { this.gaslimit = new DataWord(gaslimit); this.repository = repository; + this.blockStore = blockStore; } /* ADDRESS op */ @@ -239,6 +243,11 @@ public class ProgramInvokeImpl implements ProgramInvoke { return repository; } + @Override + public BlockStore getBlockStore() { + return blockStore; + } + @Override public boolean byTransaction() { return byTransaction; diff --git a/ethereumj-core/src/main/java/org/ethereum/vm/ProgramInvokeMockImpl.java b/ethereumj-core/src/main/java/org/ethereum/vm/ProgramInvokeMockImpl.java index beeac706..357d4ec3 100644 --- a/ethereumj-core/src/main/java/org/ethereum/vm/ProgramInvokeMockImpl.java +++ b/ethereumj-core/src/main/java/org/ethereum/vm/ProgramInvokeMockImpl.java @@ -2,6 +2,8 @@ package org.ethereum.vm; import org.ethereum.crypto.ECKey; import org.ethereum.crypto.HashUtil; +import org.ethereum.db.BlockStore; +import org.ethereum.db.BlockStoreDummy; import org.ethereum.db.RepositoryImpl; import org.ethereum.facade.Repository; @@ -214,6 +216,11 @@ public class ProgramInvokeMockImpl implements ProgramInvoke { return this.repository; } + @Override + public BlockStore getBlockStore() { + return new BlockStoreDummy(); + } + public void setRepository(Repository repository) { this.repository = repository; } 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 859e06dc..a5e8b9e1 100644 --- a/ethereumj-core/src/main/java/org/ethereum/vm/VM.java +++ b/ethereumj-core/src/main/java/org/ethereum/vm/VM.java @@ -716,13 +716,16 @@ public class VM { /** * Block Information */ - case PREVHASH: { - DataWord prevHash = program.getPrevHash(); + case BLOCKHASH: { + + int blockIndex = program.stackPop().intValue(); + + DataWord blockHash = program.getBlockHash(blockIndex); if (logger.isInfoEnabled()) - hint = "prevHash: " + prevHash; + hint = "blockHash: " + blockHash; - program.stackPush(prevHash); + program.stackPush(blockHash); program.step(); } break; diff --git a/ethereumj-core/src/test/java/test/ethereum/jsontestsuite/GitHubStateTest.java b/ethereumj-core/src/test/java/test/ethereum/jsontestsuite/GitHubStateTest.java index 97f9c0d0..f8c969fb 100644 --- a/ethereumj-core/src/test/java/test/ethereum/jsontestsuite/GitHubStateTest.java +++ b/ethereumj-core/src/test/java/test/ethereum/jsontestsuite/GitHubStateTest.java @@ -18,9 +18,8 @@ public class GitHubStateTest { @Ignore @Test public void stSingleTest() throws ParseException { - String json = JSONReader.loadJSON("StateTests/stSystemOperationsTest.json"); - GitHubJSONTestSuite.runGitHubJsonStateTest(json, "createNameRegistrator"); + GitHubJSONTestSuite.runGitHubJsonStateTest(json, "CallToReturn1ForDynamicJump1"); } @Ignore @@ -28,7 +27,7 @@ public class GitHubStateTest { public void runWithExcludedTest() throws ParseException { Set excluded = new HashSet<>(); - excluded.add("createNameRegistratorValueTooHigh"); + excluded.add("CallToReturn1ForDynamicJump1"); String json = JSONReader.loadJSON("StateTests/stSystemOperationsTest.json"); GitHubJSONTestSuite.runGitHubJsonStateTest(json, excluded); @@ -89,6 +88,14 @@ public class GitHubStateTest { } + @Test + public void stBlockHashTest() throws ParseException { + + String json = JSONReader.loadJSON("StateTests/stBlockHashTest.json"); + GitHubJSONTestSuite.runGitHubJsonStateTest(json); + } + + @Test public void stSystemOperationsTest() throws ParseException {