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:
Roman Mandeleil 2015-01-08 18:55:52 +02:00
parent 84b1cef682
commit 59833f3fd6
17 changed files with 312 additions and 208 deletions

View File

@ -1,6 +1,6 @@
package org.ethereum.core; package org.ethereum.core;
import org.ethereum.db.BlockStore; import org.ethereum.db.BlockStoreImpl;
import org.ethereum.facade.Blockchain; import org.ethereum.facade.Blockchain;
import org.ethereum.facade.Repository; import org.ethereum.facade.Repository;
import org.ethereum.listener.EthereumListener; import org.ethereum.listener.EthereumListener;
@ -79,7 +79,7 @@ public class BlockchainImpl implements Blockchain {
private Repository track; private Repository track;
@Autowired @Autowired
private BlockStore blockStore; private BlockStoreImpl blockStore;
private Block bestBlock; private Block bestBlock;
private BigInteger totalDifficulty = BigInteger.ZERO; private BigInteger totalDifficulty = BigInteger.ZERO;
@ -337,7 +337,8 @@ public class BlockchainImpl implements Blockchain {
for (Transaction tx : block.getTransactionsList()) { for (Transaction tx : block.getTransactionsList()) {
stateLogger.info("apply block: [{}] tx: [{}] ", block.getNumber(), i); 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); programInvokeFactory, block);
executor.execute(); executor.execute();

View File

@ -1,5 +1,6 @@
package org.ethereum.core; package org.ethereum.core;
import org.ethereum.db.BlockStore;
import org.ethereum.facade.Repository; import org.ethereum.facade.Repository;
import org.ethereum.vm.DataWord; import org.ethereum.vm.DataWord;
import org.ethereum.vm.GasCost; import org.ethereum.vm.GasCost;
@ -33,6 +34,8 @@ public class TransactionExecutor {
private Transaction tx; private Transaction tx;
private Repository track; private Repository track;
private BlockStore blockStore;
private ProgramInvokeFactory programInvokeFactory; private ProgramInvokeFactory programInvokeFactory;
private byte[] coinbase; private byte[] coinbase;
@ -41,12 +44,13 @@ public class TransactionExecutor {
private Block currentBlock; 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) { ProgramInvokeFactory programInvokeFactory, Block currentBlock) {
this.tx = tx; this.tx = tx;
this.coinbase = coinbase; this.coinbase = coinbase;
this.track = track; this.track = track;
this.blockStore = blockStore;
this.programInvokeFactory = programInvokeFactory; this.programInvokeFactory = programInvokeFactory;
this.currentBlock = currentBlock; this.currentBlock = currentBlock;
} }
@ -180,7 +184,7 @@ public class TransactionExecutor {
} }
ProgramInvoke programInvoke = ProgramInvoke programInvoke =
programInvokeFactory.createProgramInvoke(tx, currentBlock, trackTx); programInvokeFactory.createProgramInvoke(tx, currentBlock, trackTx, blockStore);
VM vm = new VM(); VM vm = new VM();
Program program = new Program(code, programInvoke); Program program = new Program(code, programInvoke);

View File

@ -1,179 +1,13 @@
package org.ethereum.db; package org.ethereum.db;
import org.ethereum.core.Block; 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 * @author: Roman Mandeleil
* @since 12.11.2014 * Created on: 08/01/2015 10:27
*/ */
@Repository
@Transactional(propagation = Propagation.SUPPORTS)
public class BlockStore {
@Autowired public interface BlockStore {
private SessionFactory sessionFactory;
@Autowired public byte[] getBlockHashByNumber(long blockNumber);
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);
}
} }

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -2,6 +2,7 @@ package org.ethereum.jsontestsuite;
import org.ethereum.core.Block; import org.ethereum.core.Block;
import org.ethereum.core.Transaction; import org.ethereum.core.Transaction;
import org.ethereum.db.BlockStore;
import org.ethereum.facade.Repository; import org.ethereum.facade.Repository;
import org.ethereum.util.ByteUtil; import org.ethereum.util.ByteUtil;
import org.ethereum.vm.DataWord; import org.ethereum.vm.DataWord;
@ -26,18 +27,19 @@ public class TestProgramInvokeFactory implements ProgramInvokeFactory {
@Override @Override
public ProgramInvoke createProgramInvoke(Transaction tx, Block block, Repository repository) { public ProgramInvoke createProgramInvoke(Transaction tx, Block block, Repository repository, BlockStore blockStore) {
return generalInvoke(tx, repository); return generalInvoke(tx, repository, blockStore);
} }
@Override @Override
public ProgramInvoke createProgramInvoke(Program program, DataWord toAddress, DataWord inValue, DataWord inGas, 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; return null;
} }
private ProgramInvoke generalInvoke(Transaction tx, Repository repository) { private ProgramInvoke generalInvoke(Transaction tx, Repository repository ,BlockStore blockStore) {
/*** ADDRESS op ***/ /*** ADDRESS op ***/
// YP: Get address of currently executing account. // YP: Get address of currently executing account.
@ -88,7 +90,7 @@ public class TestProgramInvokeFactory implements ProgramInvokeFactory {
return new ProgramInvokeImpl(address, origin, caller, balance, return new ProgramInvokeImpl(address, origin, caller, balance,
gasPrice, gas, callValue, data, lastHash, coinbase, gasPrice, gas, callValue, data, lastHash, coinbase,
timestamp, number, difficulty, gaslimit, repository); timestamp, number, difficulty, gaslimit, repository, blockStore);
} }
} }

View File

@ -2,6 +2,7 @@ package org.ethereum.jsontestsuite;
import org.ethereum.core.BlockchainImpl; import org.ethereum.core.BlockchainImpl;
import org.ethereum.core.TransactionExecutor; import org.ethereum.core.TransactionExecutor;
import org.ethereum.db.BlockStoreDummy;
import org.ethereum.db.ByteArrayWrapper; import org.ethereum.db.ByteArrayWrapper;
import org.ethereum.db.ContractDetails; import org.ethereum.db.ContractDetails;
import org.ethereum.db.RepositoryDummy; import org.ethereum.db.RepositoryDummy;
@ -88,8 +89,9 @@ public class TestRunner {
blockchain.startTracking(); blockchain.startTracking();
Repository track = repository.startTracking(); Repository track = repository.startTracking();
TransactionExecutor executor = new TransactionExecutor(tx, coinbase, track, TransactionExecutor executor =
invokeFactory, null); new TransactionExecutor(tx, coinbase, track, new BlockStoreDummy(),
invokeFactory, blockchain.getBestBlock());
executor.execute(); executor.execute();
track.commit(); track.commit();
@ -179,7 +181,7 @@ public class TestRunner {
ProgramInvoke programInvoke = new ProgramInvokeImpl(address, origin, caller, balance, ProgramInvoke programInvoke = new ProgramInvokeImpl(address, origin, caller, balance,
gasPrice, gas, callValue, msgData, lastHash, coinbase, gasPrice, gas, callValue, msgData, lastHash, coinbase,
timestamp, number, difficulty, gaslimit, repository, true); timestamp, number, difficulty, gaslimit, repository, null, true);
/* 3. Create Program - exec.code */ /* 3. Create Program - exec.code */
/* 4. run VM */ /* 4. run VM */

View File

@ -6,7 +6,7 @@ import org.ethereum.core.Transaction;
import org.ethereum.core.TransactionReceipt; import org.ethereum.core.TransactionReceipt;
import org.ethereum.core.Wallet; import org.ethereum.core.Wallet;
import org.ethereum.crypto.HashUtil; import org.ethereum.crypto.HashUtil;
import org.ethereum.db.BlockStore; import org.ethereum.db.BlockStoreImpl;
import org.ethereum.facade.Blockchain; import org.ethereum.facade.Blockchain;
import org.ethereum.facade.Repository; import org.ethereum.facade.Repository;
import org.ethereum.listener.EthereumListener; import org.ethereum.listener.EthereumListener;
@ -63,7 +63,7 @@ public class WorldManager {
private PeerDiscovery peerDiscovery; private PeerDiscovery peerDiscovery;
@Autowired @Autowired
private BlockStore blockStore; private BlockStoreImpl blockStore;
@Autowired @Autowired
private ChannelManager channelManager; private ChannelManager channelManager;

View File

@ -190,7 +190,7 @@ public enum OpCode {
* (0x40) Get hash of most recent * (0x40) Get hash of most recent
* complete block * complete block
*/ */
PREVHASH(0x40, 0), BLOCKHASH(0x40, 1),
/** /**
* (0x41) Get the blocks coinbase address * (0x41) Get the blocks coinbase address
*/ */

View File

@ -1,6 +1,7 @@
package org.ethereum.vm; package org.ethereum.vm;
import org.ethereum.crypto.HashUtil; import org.ethereum.crypto.HashUtil;
import org.ethereum.db.BlockStore;
import org.ethereum.db.ContractDetails; import org.ethereum.db.ContractDetails;
import org.ethereum.facade.Repository; import org.ethereum.facade.Repository;
import org.ethereum.util.ByteUtil; import org.ethereum.util.ByteUtil;
@ -350,7 +351,7 @@ public class Program {
// [5] COOK THE INVOKE AND EXECUTE // [5] COOK THE INVOKE AND EXECUTE
ProgramInvoke programInvoke = programInvokeFactory.createProgramInvoke( ProgramInvoke programInvoke = programInvokeFactory.createProgramInvoke(
this, new DataWord(newAddress), DataWord.ZERO, gasLimit, this, new DataWord(newAddress), DataWord.ZERO, gasLimit,
newBalance, null, track); newBalance, null, track, this.invokeData.getBlockStore());
ProgramResult result = null; ProgramResult result = null;
@ -466,7 +467,7 @@ public class Program {
Repository trackRepository = result.getRepository().startTracking(); Repository trackRepository = result.getRepository().startTracking();
ProgramInvoke programInvoke = programInvokeFactory.createProgramInvoke( ProgramInvoke programInvoke = programInvokeFactory.createProgramInvoke(
this, new DataWord(contextAddress), msg.getEndowment(), this, new DataWord(contextAddress), msg.getEndowment(),
msg.getGas(), contextBalance, data, trackRepository); msg.getGas(), contextBalance, data, trackRepository, this.invokeData.getBlockStore());
ProgramResult result = null; ProgramResult result = null;
@ -574,6 +575,22 @@ public class Program {
return this.programAddress.clone(); 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) { public DataWord getBalance(DataWord address) {
if (invokeData == null) return DataWord.ZERO_EMPTY_ARRAY; if (invokeData == null) return DataWord.ZERO_EMPTY_ARRAY;

View File

@ -1,5 +1,6 @@
package org.ethereum.vm; package org.ethereum.vm;
import org.ethereum.db.BlockStore;
import org.ethereum.facade.Repository; import org.ethereum.facade.Repository;
/** /**
@ -41,12 +42,15 @@ public interface ProgramInvoke {
public DataWord getDifficulty(); public DataWord getDifficulty();
public DataWord getGaslimit(); public DataWord getGaslimit();
public Repository getRepository();
public boolean byTransaction(); public boolean byTransaction();
boolean byTestingSuite(); boolean byTestingSuite();
public int getCallDeep(); public int getCallDeep();
public Repository getRepository();
public BlockStore getBlockStore();
} }

View File

@ -2,6 +2,7 @@ package org.ethereum.vm;
import org.ethereum.core.Block; import org.ethereum.core.Block;
import org.ethereum.core.Transaction; import org.ethereum.core.Transaction;
import org.ethereum.db.BlockStore;
import org.ethereum.facade.Repository; import org.ethereum.facade.Repository;
import java.math.BigInteger; import java.math.BigInteger;
@ -12,12 +13,13 @@ import java.math.BigInteger;
*/ */
public interface ProgramInvokeFactory { 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, public ProgramInvoke createProgramInvoke(Program program, DataWord toAddress,
DataWord inValue, DataWord inGas, DataWord inValue, DataWord inGas,
BigInteger balanceInt, byte[] dataIn, BigInteger balanceInt, byte[] dataIn,
Repository repository); Repository repository, BlockStore blockStore);
} }

View File

@ -2,6 +2,8 @@ package org.ethereum.vm;
import org.ethereum.core.Block; import org.ethereum.core.Block;
import org.ethereum.core.Transaction; import org.ethereum.core.Transaction;
import org.ethereum.db.BlockStore;
import org.ethereum.db.BlockStoreImpl;
import org.ethereum.facade.Blockchain; import org.ethereum.facade.Blockchain;
import org.ethereum.facade.Repository; import org.ethereum.facade.Repository;
import org.ethereum.util.ByteUtil; import org.ethereum.util.ByteUtil;
@ -27,11 +29,15 @@ public class ProgramInvokeFactoryImpl implements ProgramInvokeFactory {
@Autowired @Autowired
private Blockchain blockchain; private Blockchain blockchain;
@Autowired
private BlockStoreImpl blockStore;
// Invocation by the wire tx // Invocation by the wire tx
@Override @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 // https://ethereum.etherpad.mozilla.org/26
Block lastBlock = blockchain.getBestBlock(); Block lastBlock = blockchain.getBestBlock();
@ -119,7 +125,7 @@ public class ProgramInvokeFactoryImpl implements ProgramInvokeFactory {
ProgramInvoke programInvoke = ProgramInvoke programInvoke =
new ProgramInvokeImpl(address, origin, caller, balance, gasPrice, gas, callValue, data, new ProgramInvokeImpl(address, origin, caller, balance, gasPrice, gas, callValue, data,
lastHash, coinbase, timestamp, number, difficulty, gaslimit, lastHash, coinbase, timestamp, number, difficulty, gaslimit,
repository); repository, blockStore);
return programInvoke; return programInvoke;
} }
@ -131,7 +137,7 @@ public class ProgramInvokeFactoryImpl implements ProgramInvokeFactory {
public ProgramInvoke createProgramInvoke(Program program, DataWord toAddress, public ProgramInvoke createProgramInvoke(Program program, DataWord toAddress,
DataWord inValue, DataWord inGas, DataWord inValue, DataWord inGas,
BigInteger balanceInt, byte[] dataIn, BigInteger balanceInt, byte[] dataIn,
Repository repository) { Repository repository, BlockStore blockStore) {
DataWord address = toAddress; DataWord address = toAddress;
DataWord origin = program.getOriginAddress(); DataWord origin = program.getOriginAddress();
@ -184,6 +190,6 @@ public class ProgramInvokeFactoryImpl implements ProgramInvokeFactory {
return new ProgramInvokeImpl(address, origin, caller, balance, gasPrice, gas, callValue, return new ProgramInvokeImpl(address, origin, caller, balance, gasPrice, gas, callValue,
data, lastHash, coinbase, timestamp, number, difficulty, gasLimit, data, lastHash, coinbase, timestamp, number, difficulty, gasLimit,
repository, program.invokeData.getCallDeep() + 1); repository, program.invokeData.getCallDeep() + 1, blockStore);
} }
} }

View File

@ -1,5 +1,6 @@
package org.ethereum.vm; package org.ethereum.vm;
import org.ethereum.db.BlockStore;
import org.ethereum.facade.Repository; import org.ethereum.facade.Repository;
import java.math.BigInteger; import java.math.BigInteger;
@ -13,6 +14,7 @@ import java.util.Map;
*/ */
public class ProgramInvokeImpl implements ProgramInvoke { public class ProgramInvokeImpl implements ProgramInvoke {
private BlockStore blockStore;
/** /**
* TRANSACTION env ** * TRANSACTION env **
*/ */
@ -39,7 +41,7 @@ public class ProgramInvokeImpl implements ProgramInvoke {
DataWord gasPrice, DataWord gas, DataWord callValue, byte[] msgData, DataWord gasPrice, DataWord gas, DataWord callValue, byte[] msgData,
DataWord lastHash, DataWord coinbase, DataWord timestamp, DataWord number, DataWord DataWord lastHash, DataWord coinbase, DataWord timestamp, DataWord number, DataWord
difficulty, difficulty,
DataWord gaslimit, Repository repository, int callDeep) { DataWord gaslimit, Repository repository, int callDeep, BlockStore blockStore) {
// Transaction env // Transaction env
this.address = address; this.address = address;
@ -62,15 +64,16 @@ public class ProgramInvokeImpl implements ProgramInvoke {
this.repository = repository; this.repository = repository;
this.byTransaction = false; this.byTransaction = false;
this.callDeep = callDeep; this.callDeep = callDeep;
this.blockStore = blockStore;
} }
public ProgramInvokeImpl(byte[] address, byte[] origin, byte[] caller, byte[] balance, public ProgramInvokeImpl(byte[] address, byte[] origin, byte[] caller, byte[] balance,
byte[] gasPrice, byte[] gas, byte[] callValue, byte[] msgData, byte[] gasPrice, byte[] gas, byte[] callValue, byte[] msgData,
byte[] lastHash, byte[] coinbase, long timestamp, long number, byte[] difficulty, byte[] lastHash, byte[] coinbase, long timestamp, long number, byte[] difficulty,
long gaslimit, long gaslimit,
Repository repository, boolean byTestingSuite) { Repository repository, BlockStore blockStore,boolean byTestingSuite) {
this(address, origin, caller, balance, gasPrice, gas, callValue, msgData, lastHash, coinbase, 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; this.byTestingSuite = byTestingSuite;
} }
@ -79,7 +82,7 @@ public class ProgramInvokeImpl implements ProgramInvoke {
byte[] gasPrice, byte[] gas, byte[] callValue, byte[] msgData, byte[] gasPrice, byte[] gas, byte[] callValue, byte[] msgData,
byte[] lastHash, byte[] coinbase, long timestamp, long number, byte[] difficulty, byte[] lastHash, byte[] coinbase, long timestamp, long number, byte[] difficulty,
long gaslimit, long gaslimit,
Repository repository) { Repository repository, BlockStore blockStore) {
// Transaction env // Transaction env
this.address = new DataWord(address); this.address = new DataWord(address);
@ -100,6 +103,7 @@ public class ProgramInvokeImpl implements ProgramInvoke {
this.gaslimit = new DataWord(gaslimit); this.gaslimit = new DataWord(gaslimit);
this.repository = repository; this.repository = repository;
this.blockStore = blockStore;
} }
/* ADDRESS op */ /* ADDRESS op */
@ -239,6 +243,11 @@ public class ProgramInvokeImpl implements ProgramInvoke {
return repository; return repository;
} }
@Override
public BlockStore getBlockStore() {
return blockStore;
}
@Override @Override
public boolean byTransaction() { public boolean byTransaction() {
return byTransaction; return byTransaction;

View File

@ -2,6 +2,8 @@ package org.ethereum.vm;
import org.ethereum.crypto.ECKey; import org.ethereum.crypto.ECKey;
import org.ethereum.crypto.HashUtil; import org.ethereum.crypto.HashUtil;
import org.ethereum.db.BlockStore;
import org.ethereum.db.BlockStoreDummy;
import org.ethereum.db.RepositoryImpl; import org.ethereum.db.RepositoryImpl;
import org.ethereum.facade.Repository; import org.ethereum.facade.Repository;
@ -214,6 +216,11 @@ public class ProgramInvokeMockImpl implements ProgramInvoke {
return this.repository; return this.repository;
} }
@Override
public BlockStore getBlockStore() {
return new BlockStoreDummy();
}
public void setRepository(Repository repository) { public void setRepository(Repository repository) {
this.repository = repository; this.repository = repository;
} }

View File

@ -716,13 +716,16 @@ public class VM {
/** /**
* Block Information * Block Information
*/ */
case PREVHASH: { case BLOCKHASH: {
DataWord prevHash = program.getPrevHash();
int blockIndex = program.stackPop().intValue();
DataWord blockHash = program.getBlockHash(blockIndex);
if (logger.isInfoEnabled()) if (logger.isInfoEnabled())
hint = "prevHash: " + prevHash; hint = "blockHash: " + blockHash;
program.stackPush(prevHash); program.stackPush(blockHash);
program.step(); program.step();
} }
break; break;

View File

@ -18,9 +18,8 @@ public class GitHubStateTest {
@Ignore @Ignore
@Test @Test
public void stSingleTest() throws ParseException { public void stSingleTest() throws ParseException {
String json = JSONReader.loadJSON("StateTests/stSystemOperationsTest.json"); String json = JSONReader.loadJSON("StateTests/stSystemOperationsTest.json");
GitHubJSONTestSuite.runGitHubJsonStateTest(json, "createNameRegistrator"); GitHubJSONTestSuite.runGitHubJsonStateTest(json, "CallToReturn1ForDynamicJump1");
} }
@Ignore @Ignore
@ -28,7 +27,7 @@ public class GitHubStateTest {
public void runWithExcludedTest() throws ParseException { public void runWithExcludedTest() throws ParseException {
Set<String> excluded = new HashSet<>(); Set<String> excluded = new HashSet<>();
excluded.add("createNameRegistratorValueTooHigh"); excluded.add("CallToReturn1ForDynamicJump1");
String json = JSONReader.loadJSON("StateTests/stSystemOperationsTest.json"); String json = JSONReader.loadJSON("StateTests/stSystemOperationsTest.json");
GitHubJSONTestSuite.runGitHubJsonStateTest(json, excluded); 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 @Test
public void stSystemOperationsTest() throws ParseException { public void stSystemOperationsTest() throws ParseException {