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