Fix BLOCKHASH op new rule
The blockhash retrieved by index on one of the recent 256 blocks. If the index is out of that window zero pushed into the stack as a result
This commit is contained in:
parent
84b1cef682
commit
59833f3fd6
|
@ -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();
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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<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;
|
||||
}
|
||||
|
||||
@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<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);
|
||||
}
|
||||
|
||||
@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<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;
|
||||
}
|
||||
|
||||
@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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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<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;
|
||||
}
|
||||
|
||||
@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<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);
|
||||
}
|
||||
|
||||
@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<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;
|
||||
}
|
||||
|
||||
@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);
|
||||
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
*/
|
||||
|
|
|
@ -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<u256>(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;
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package org.ethereum.vm;
|
||||
|
||||
import org.ethereum.db.BlockStore;
|
||||
import org.ethereum.facade.Repository;
|
||||
|
||||
/**
|
||||
|
@ -42,11 +43,14 @@ public interface ProgramInvoke {
|
|||
|
||||
public DataWord getGaslimit();
|
||||
|
||||
public Repository getRepository();
|
||||
|
||||
public boolean byTransaction();
|
||||
|
||||
boolean byTestingSuite();
|
||||
|
||||
public int getCallDeep();
|
||||
|
||||
public Repository getRepository();
|
||||
|
||||
public BlockStore getBlockStore();
|
||||
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
@ -28,10 +30,14 @@ 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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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<String> 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 {
|
||||
|
||||
|
|
Loading…
Reference in New Issue