Fix memory allocation and add unit tests

This commit is contained in:
nicksavers 2014-09-09 01:35:39 +02:00
parent c51e56831a
commit 561d1dd296
22 changed files with 556 additions and 203 deletions

View File

@ -1,6 +1,7 @@
package org.ethereum.core; package org.ethereum.core;
import org.ethereum.db.Repository; import org.ethereum.db.RepositoryImpl;
import org.ethereum.facade.Blockchain;
import org.ethereum.listener.EthereumListener; import org.ethereum.listener.EthereumListener;
import org.ethereum.manager.WorldManager; import org.ethereum.manager.WorldManager;
import org.ethereum.net.BlockQueue; import org.ethereum.net.BlockQueue;
@ -50,7 +51,7 @@ import static org.ethereum.core.Denomination.SZABO;
* Created on: 20/05/2014 10:44 * Created on: 20/05/2014 10:44
* *
*/ */
public class Blockchain implements org.ethereum.facade.Blockchain{ public class BlockchainImpl implements Blockchain {
private static final Logger logger = LoggerFactory.getLogger("blockchain"); private static final Logger logger = LoggerFactory.getLogger("blockchain");
private static final Logger stateLogger = LoggerFactory.getLogger("state"); private static final Logger stateLogger = LoggerFactory.getLogger("state");
@ -58,7 +59,7 @@ public class Blockchain implements org.ethereum.facade.Blockchain{
// to avoid using minGasPrice=0 from Genesis for the wallet // to avoid using minGasPrice=0 from Genesis for the wallet
private static final long INITIAL_MIN_GAS_PRICE = 10 * SZABO.longValue(); private static final long INITIAL_MIN_GAS_PRICE = 10 * SZABO.longValue();
private Repository repository; private RepositoryImpl repository;
private Block lastBlock; private Block lastBlock;
// keep the index of the chain for // keep the index of the chain for
@ -67,7 +68,7 @@ public class Blockchain implements org.ethereum.facade.Blockchain{
private final BlockQueue blockQueue = new BlockQueue(); private final BlockQueue blockQueue = new BlockQueue();
public Blockchain(Repository repository) { public BlockchainImpl(RepositoryImpl repository) {
this.repository = repository; this.repository = repository;
} }
@ -324,7 +325,7 @@ public class Blockchain implements org.ethereum.facade.Blockchain{
if (isContractCreation || code != null) { if (isContractCreation || code != null) {
// START TRACKING FOR REVERT CHANGES OPTION // START TRACKING FOR REVERT CHANGES OPTION
Repository trackRepository = repository.getTrack(); RepositoryImpl trackRepository = repository.getTrack();
trackRepository.startTracking(); trackRepository.startTracking();
try { try {
@ -385,7 +386,7 @@ public class Blockchain implements org.ethereum.facade.Blockchain{
* @param contractAddress * @param contractAddress
*/ */
private void applyProgramResult(ProgramResult result, BigInteger gasDebit, private void applyProgramResult(ProgramResult result, BigInteger gasDebit,
Repository repository, byte[] senderAddress, RepositoryImpl repository, byte[] senderAddress,
byte[] contractAddress, byte[] coinbase, boolean initResults) { byte[] contractAddress, byte[] coinbase, boolean initResults) {
if (result.getException() != null if (result.getException() != null

View File

@ -3,9 +3,10 @@ package org.ethereum.db;
import org.codehaus.plexus.util.FileUtils; import org.codehaus.plexus.util.FileUtils;
import org.ethereum.core.AccountState; import org.ethereum.core.AccountState;
import org.ethereum.core.Block; import org.ethereum.core.Block;
import org.ethereum.core.Blockchain; import org.ethereum.core.BlockchainImpl;
import org.ethereum.core.Genesis; import org.ethereum.core.Genesis;
import org.ethereum.crypto.HashUtil; import org.ethereum.crypto.HashUtil;
import org.ethereum.facade.Repository;
import org.ethereum.json.EtherObjectMapper; import org.ethereum.json.EtherObjectMapper;
import org.ethereum.json.JSONHelper; import org.ethereum.json.JSONHelper;
import org.ethereum.listener.EthereumListener; import org.ethereum.listener.EthereumListener;
@ -18,6 +19,7 @@ import org.iq80.leveldb.DBIterator;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.spongycastle.util.encoders.Hex; import org.spongycastle.util.encoders.Hex;
import com.fasterxml.jackson.databind.node.JsonNodeFactory; import com.fasterxml.jackson.databind.node.JsonNodeFactory;
import com.fasterxml.jackson.databind.node.ObjectNode; import com.fasterxml.jackson.databind.node.ObjectNode;
@ -51,7 +53,7 @@ import static org.ethereum.config.SystemProperties.CONFIG;
* @author: Roman Mandeleil * @author: Roman Mandeleil
* Created on: 23/06/2014 23:01 * Created on: 23/06/2014 23:01
*/ */
public class Repository implements org.ethereum.facade.Repository{ public class RepositoryImpl implements Repository {
private Logger logger = LoggerFactory.getLogger("repository"); private Logger logger = LoggerFactory.getLogger("repository");
@ -72,7 +74,7 @@ public class Repository implements org.ethereum.facade.Repository{
* *
* @See loadBlockchain() to update the stateRoot * @See loadBlockchain() to update the stateRoot
*/ */
public Repository() { public RepositoryImpl() {
chainDB = new DatabaseImpl("blockchain"); chainDB = new DatabaseImpl("blockchain");
detailsDB = new DatabaseImpl("details"); detailsDB = new DatabaseImpl("details");
contractDetailsDB = new TrackDatabase(detailsDB); contractDetailsDB = new TrackDatabase(detailsDB);
@ -81,15 +83,15 @@ public class Repository implements org.ethereum.facade.Repository{
accountStateDB = new TrackTrie(worldState); accountStateDB = new TrackTrie(worldState);
} }
private Repository(TrackTrie accountStateDB, TrackDatabase contractDetailsDB) { private RepositoryImpl(TrackTrie accountStateDB, TrackDatabase contractDetailsDB) {
this.accountStateDB = accountStateDB; this.accountStateDB = accountStateDB;
this.contractDetailsDB = contractDetailsDB; this.contractDetailsDB = contractDetailsDB;
} }
public Repository getTrack() { public RepositoryImpl getTrack() {
TrackTrie trackState = new TrackTrie(accountStateDB); TrackTrie trackState = new TrackTrie(accountStateDB);
TrackDatabase trackDetails = new TrackDatabase(contractDetailsDB); TrackDatabase trackDetails = new TrackDatabase(contractDetailsDB);
return new Repository (trackState, trackDetails); return new RepositoryImpl (trackState, trackDetails);
} }
public void startTracking() { public void startTracking() {
@ -121,8 +123,8 @@ public class Repository implements org.ethereum.facade.Repository{
this.worldState.sync(); this.worldState.sync();
} }
public Blockchain loadBlockchain() { public BlockchainImpl loadBlockchain() {
Blockchain blockchain = WorldManager.getInstance().getBlockchain(); BlockchainImpl blockchain = WorldManager.getInstance().getBlockchain();
DBIterator iterator = chainDB.iterator(); DBIterator iterator = chainDB.iterator();
try { try {
if (!iterator.hasNext()) { if (!iterator.hasNext()) {

View File

@ -7,7 +7,7 @@ import java.util.concurrent.Future;
import org.ethereum.core.Transaction; import org.ethereum.core.Transaction;
import org.ethereum.core.Wallet; import org.ethereum.core.Wallet;
import org.ethereum.db.Repository; import org.ethereum.db.RepositoryImpl;
import org.ethereum.listener.EthereumListener; import org.ethereum.listener.EthereumListener;
import org.ethereum.manager.WorldManager; import org.ethereum.manager.WorldManager;
import org.ethereum.net.client.ClientPeer; import org.ethereum.net.client.ClientPeer;
@ -195,7 +195,7 @@ public class EthereumImpl implements Ethereum {
@Override @Override
public Repository getRepository(){ public RepositoryImpl getRepository(){
return WorldManager.getInstance().getRepository(); return WorldManager.getInstance().getRepository();
} }

View File

@ -3,8 +3,6 @@ package org.ethereum.facade;
import org.ethereum.core.AccountState; import org.ethereum.core.AccountState;
import org.ethereum.db.ContractDetails; import org.ethereum.db.ContractDetails;
import java.math.BigInteger;
/** /**
* www.ethereumJ.com * www.ethereumJ.com
* *
@ -16,5 +14,4 @@ public interface Repository {
public AccountState getAccountState(byte[] addr); public AccountState getAccountState(byte[] addr);
public ContractDetails getContractDetails(byte[] addr); public ContractDetails getContractDetails(byte[] addr);
} }

View File

@ -4,7 +4,7 @@ import org.ethereum.core.AccountState;
import org.ethereum.core.Block; import org.ethereum.core.Block;
import org.ethereum.db.ByteArrayWrapper; import org.ethereum.db.ByteArrayWrapper;
import org.ethereum.db.ContractDetails; import org.ethereum.db.ContractDetails;
import org.ethereum.db.Repository; import org.ethereum.db.RepositoryImpl;
import org.ethereum.util.ByteUtil; import org.ethereum.util.ByteUtil;
import org.ethereum.vm.DataWord; import org.ethereum.vm.DataWord;
import org.spongycastle.util.encoders.Hex; import org.spongycastle.util.encoders.Hex;
@ -67,7 +67,7 @@ public class JSONHelper {
public static void dumpBlock(ObjectNode blockNode, Block block, public static void dumpBlock(ObjectNode blockNode, Block block,
long gasUsed, byte[] state, List<ByteArrayWrapper> keys, long gasUsed, byte[] state, List<ByteArrayWrapper> keys,
Repository repository) { RepositoryImpl repository) {
blockNode.put("coinbase", Hex.toHexString(block.getCoinbase())); blockNode.put("coinbase", Hex.toHexString(block.getCoinbase()));
blockNode.put("difficulty", new BigInteger(1, block.calcDifficulty()).toString()); blockNode.put("difficulty", new BigInteger(1, block.calcDifficulty()).toString());

View File

@ -2,7 +2,7 @@ package org.ethereum.jsontestsuite;
import org.ethereum.db.ByteArrayWrapper; import org.ethereum.db.ByteArrayWrapper;
import org.ethereum.db.ContractDetails; import org.ethereum.db.ContractDetails;
import org.ethereum.db.Repository; import org.ethereum.db.RepositoryImpl;
import org.ethereum.util.ByteUtil; import org.ethereum.util.ByteUtil;
import org.ethereum.vm.*; import org.ethereum.vm.*;
import org.slf4j.Logger; import org.slf4j.Logger;
@ -46,7 +46,7 @@ public class TestRunner {
List<String> results = new ArrayList<>(); List<String> results = new ArrayList<>();
Repository repository = new Repository(); RepositoryImpl repository = new RepositoryImpl();
/* 1. Store pre-exist accounts - Pre */ /* 1. Store pre-exist accounts - Pre */
for (ByteArrayWrapper key : testCase.getPre().keySet()){ for (ByteArrayWrapper key : testCase.getPre().keySet()){

View File

@ -2,17 +2,14 @@ package org.ethereum.manager;
import static org.ethereum.config.SystemProperties.CONFIG; import static org.ethereum.config.SystemProperties.CONFIG;
import java.math.BigInteger;
import java.net.InetAddress; import java.net.InetAddress;
import java.net.UnknownHostException; import java.net.UnknownHostException;
import java.util.*; import java.util.*;
import org.ethereum.core.AccountState; import org.ethereum.core.BlockchainImpl;
import org.ethereum.core.Blockchain;
import org.ethereum.core.Wallet; import org.ethereum.core.Wallet;
import org.ethereum.crypto.ECKey;
import org.ethereum.crypto.HashUtil; import org.ethereum.crypto.HashUtil;
import org.ethereum.db.Repository; import org.ethereum.db.RepositoryImpl;
import org.ethereum.listener.EthereumListener; import org.ethereum.listener.EthereumListener;
import org.ethereum.net.client.ClientPeer; import org.ethereum.net.client.ClientPeer;
import org.ethereum.net.client.PeerData; import org.ethereum.net.client.PeerData;
@ -28,8 +25,8 @@ import org.ethereum.net.peerdiscovery.PeerDiscovery;
*/ */
public class WorldManager { public class WorldManager {
private Blockchain blockchain; private BlockchainImpl blockchain;
private Repository repository; private RepositoryImpl repository;
private Wallet wallet; private Wallet wallet;
private PeerDiscovery peerDiscovery; private PeerDiscovery peerDiscovery;
@ -48,8 +45,8 @@ public class WorldManager {
} }
private WorldManager() { private WorldManager() {
this.repository = new Repository(); this.repository = new RepositoryImpl();
this.blockchain = new Blockchain(repository); this.blockchain = new BlockchainImpl(repository);
// Initialize PeerData // Initialize PeerData
List<PeerData> peerDataList = parsePeerDiscoveryIpList(CONFIG.peerDiscoveryIPList()); List<PeerData> peerDataList = parsePeerDiscoveryIpList(CONFIG.peerDiscoveryIPList());
@ -60,17 +57,15 @@ public class WorldManager {
} }
// used for testing // used for testing
public void reset(){ public void reset() {
this.repository = new RepositoryImpl();
this.repository = new Repository(); this.blockchain = new BlockchainImpl(repository);
this.blockchain = new Blockchain(repository);
} }
public void init(){ public void init() {
this.wallet = new Wallet();
this.wallet = new Wallet();
byte[] cowAddr = HashUtil.sha3("cow".getBytes()); byte[] cowAddr = HashUtil.sha3("cow".getBytes());
ECKey key = ECKey.fromPrivate(cowAddr);
wallet.importKey(cowAddr); wallet.importKey(cowAddr);
// AccountState state = wallet.getAccountState(key.getAddress()); // AccountState state = wallet.getAccountState(key.getAddress());
@ -79,20 +74,19 @@ public class WorldManager {
String secret = CONFIG.coinbaseSecret(); String secret = CONFIG.coinbaseSecret();
byte[] cbAddr = HashUtil.sha3(secret.getBytes()); byte[] cbAddr = HashUtil.sha3(secret.getBytes());
wallet.importKey(cbAddr); wallet.importKey(cbAddr);
} }
public static WorldManager getInstance() { public static WorldManager getInstance() {
return WorldManagerHolder.instance; return WorldManagerHolder.instance;
} }
public void addListener(EthereumListener listener){ public void addListener(EthereumListener listener) {
this.listener = listener; this.listener = listener;
} }
public void addPeers(final Set<PeerData> newPeers) { public void addPeers(final Set<PeerData> newPeers) {
synchronized (peers){ synchronized (peers) {
for (final PeerData peer : newPeers) { for (final PeerData peer : newPeers) {
if (peerDiscovery.isStarted() && !peers.contains(peer)) { if (peerDiscovery.isStarted() && !peers.contains(peer)) {
peerDiscovery.addNewPeerData(peer); peerDiscovery.addNewPeerData(peer);
@ -149,11 +143,11 @@ public class WorldManager {
this.wallet = wallet; this.wallet = wallet;
} }
public Repository getRepository() { public RepositoryImpl getRepository() {
return repository; return repository;
} }
public Blockchain getBlockchain() { public BlockchainImpl getBlockchain() {
return blockchain; return blockchain;
} }

View File

@ -6,6 +6,7 @@ import org.spongycastle.util.Arrays;
import org.spongycastle.util.encoders.Hex; import org.spongycastle.util.encoders.Hex;
import java.math.BigInteger; import java.math.BigInteger;
import java.math.BigDecimal;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
/** /**
@ -41,15 +42,12 @@ public class DataWord implements Comparable<DataWord> {
} }
public DataWord(byte[] data) { public DataWord(byte[] data) {
if (data == null)
if (data == null) { this.data = ByteUtil.EMPTY_BYTE_ARRAY;
this.data = new byte[] {}; else if (data.length <= 32)
return; System.arraycopy(data, 0, this.data, 32 - data.length, data.length);
} else
throw new RuntimeException("Data word can't exit 32 bytes: " + data);
if (data.length > 32)
throw new RuntimeException("Data word can't exit 32 bytes: " + data);
System.arraycopy(data, 0, this.data, 32 - data.length, data.length);
} }
public byte[] getData() { public byte[] getData() {
@ -67,12 +65,32 @@ public class DataWord implements Comparable<DataWord> {
return new BigInteger(1, data); return new BigInteger(1, data);
} }
/**
* Converts this DataWord to an int, checking for lost information.
* If this DataWord is out of the possible range for an int result
* then an ArithmeticException is thrown.
*
* @return this DataWord converted to an int.
* @throws ArithmeticException - if this will not fit in an int.
*/
public int intValue() { public int intValue() {
return new BigInteger(1, data).intValue(); // FIXME: Disabled for POC5
// BigDecimal tmpValue = new BigDecimal(this.value());
// return tmpValue.intValueExact();
return this.value().intValue();
} }
/**
* Converts this DataWord to a long, checking for lost information.
* If this DataWord is out of the possible range for a long result
* then an ArithmeticException is thrown.
*
* @return this DataWord converted to a long.
* @throws ArithmeticException - if this will not fit in a long.
*/
public long longValue() { public long longValue() {
return new BigInteger(1, data).longValue(); BigDecimal tmpValue = new BigDecimal(this.value());
return tmpValue.longValueExact();
} }
public BigInteger sValue() { public BigInteger sValue() {
@ -219,7 +237,7 @@ public class DataWord implements Comparable<DataWord> {
// TODO: improve with no BigInteger // TODO: improve with no BigInteger
public void exp(DataWord word) { public void exp(DataWord word) {
BigInteger result = value().pow(word.value().intValue()); BigInteger result = value().pow(word.intValue());
byte[] bytes = result.toByteArray(); byte[] bytes = result.toByteArray();
ByteBuffer data = ByteBuffer.allocate(32); ByteBuffer data = ByteBuffer.allocate(32);
@ -300,4 +318,4 @@ public class DataWord implements Comparable<DataWord> {
data, 0, data.length, data, 0, data.length,
o.getData(), 0, o.getData().length); o.getData(), 0, o.getData().length);
} }
} }

View File

@ -2,7 +2,7 @@ package org.ethereum.vm;
import org.ethereum.crypto.HashUtil; import org.ethereum.crypto.HashUtil;
import org.ethereum.db.ContractDetails; import org.ethereum.db.ContractDetails;
import org.ethereum.db.Repository; import org.ethereum.db.RepositoryImpl;
import org.ethereum.util.ByteUtil; import org.ethereum.util.ByteUtil;
import org.ethereum.util.Utils; import org.ethereum.util.Utils;
import org.slf4j.Logger; import org.slf4j.Logger;
@ -43,16 +43,17 @@ public class Program {
ProgramInvoke invokeData; ProgramInvoke invokeData;
public Program(byte[] ops, ProgramInvoke invokeData) { public Program(byte[] ops, ProgramInvoke invokeData) {
this.invokeHash = invokeData.hashCode(); if (ops == null) ops = ByteUtil.EMPTY_BYTE_ARRAY;
result.setRepository(invokeData.getRepository());
if (ops == null) ops = new byte[0]; //throw new RuntimeException("program can not run with ops: null");
this.invokeData = invokeData;
this.ops = ops; this.ops = ops;
this.programAddress = invokeData.getOwnerAddress();
} if (invokeData != null) {
this.invokeData = invokeData;
this.programAddress = invokeData.getOwnerAddress();
this.invokeHash = invokeData.hashCode();
this.result.setRepository(invokeData.getRepository());
}
}
public byte getCurrentOp() { public byte getCurrentOp() {
if(ops.length == 0) if(ops.length == 0)
@ -93,7 +94,7 @@ public class Program {
public void setPC(DataWord pc) { public void setPC(DataWord pc) {
this.pc = pc.value().intValue(); this.pc = pc.intValue();
if (this.pc == ops.length) { if (this.pc == ops.length) {
stop(); stop();
@ -162,71 +163,79 @@ public class Program {
} }
public void memorySave(DataWord addrB, DataWord value) { public void memorySave(DataWord addrB, DataWord value) {
memorySave(addrB.getData(), value.getData()); memorySave(addrB.intValue(), value.getData());
} }
public void memorySave(byte[] addr, byte[] value) { public void memorySave(int addr, byte[] value) {
memorySave(addr, value.length, value);
int address = new BigInteger(1, addr).intValue();
allocateMemory(address, value);
System.arraycopy(value, 0, memory.array(), address, value.length);
} }
/**
* Allocates a piece of memory and stores value at given offset address
*
* @param addr is the offset address
* @param allocSize size of memory needed to write
* @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);
}
public DataWord memoryLoad(DataWord addr) { public DataWord memoryLoad(DataWord addr) {
return memoryLoad(addr.intValue());
}
public DataWord memoryLoad(int address) {
int address = new BigInteger(1, addr.getData()).intValue(); allocateMemory(address, DataWord.ZERO.getData().length);
allocateMemory(address, DataWord.ZERO.getData());
byte[] data = new byte[32]; DataWord newMem = new DataWord();
System.arraycopy(memory.array(), address, data , 0 ,32); System.arraycopy(memory.array(), address, newMem.getData(), 0, newMem.getData().length);
return new DataWord(data); return newMem;
} }
public ByteBuffer memoryChunk(DataWord offsetData, DataWord sizeData) { public ByteBuffer memoryChunk(DataWord offsetData, DataWord sizeData) {
return memoryChunk(offsetData.intValue(), sizeData.intValue());
}
int offset = offsetData.intValue(); /**
int size = sizeData.intValue(); * Returns a piece of memory from a given offset and specified size
byte[] chunk = new byte[size]; * If the offset + size exceed the current memory-size,
allocateMemory(offset, new byte[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) {
if (memory != null) { allocateMemory(offset, size);
if (memory.limit() < offset + size) size = memory.limit() - offset; byte[] chunk;
System.arraycopy(memory.array(), offset, chunk, 0, size); if (memory != null)
} chunk = Arrays.copyOfRange(memory.array(), offset, offset+size);
else
chunk = new byte[size];
return ByteBuffer.wrap(chunk); return ByteBuffer.wrap(chunk);
} }
private void allocateMemory(int address, byte[] value) { /**
* Allocates extra memory in the program for
* a specified size, calculated from a given offset
*
* @param offset the memory address offset
* @param size the number of bytes to allocate
*/
protected void allocateMemory(int offset, int size) {
int memSize = 0; int memSize = memory != null ? memory.limit(): 0;
if (memory != null) memSize = memory.limit(); double newMemSize = Math.max(memSize, Math.ceil((double)(offset + size) / 32) * 32);
ByteBuffer tmpMem = ByteBuffer.allocate((int)newMemSize);
// check if you need to allocate if (memory != null)
if (memSize < (address + value.length)) { tmpMem.put(memory.array(), 0, memory.limit());
memory = tmpMem;
long overlap = memSize - address;
int sizeToAllocate = 0;
if (memSize > address) {
sizeToAllocate = memSize + value.length;
} else {
sizeToAllocate = memSize + (address - memSize) + value.length;
}
if (overlap > 0) sizeToAllocate -= overlap;
// complete to 32
sizeToAllocate = (sizeToAllocate % 32)==0 ? sizeToAllocate :
sizeToAllocate + (32 - sizeToAllocate % 32);
sizeToAllocate = (sizeToAllocate == 0)? 32: sizeToAllocate;
ByteBuffer tmpMem = ByteBuffer.allocate(sizeToAllocate);
if (memory != null)
System.arraycopy(memory.array(), 0, tmpMem.array(), 0, memory.limit());
memory = tmpMem;
}
} }
public void suicide(DataWord obtainer) { public void suicide(DataWord obtainer) {
@ -282,13 +291,13 @@ public class Program {
result.getRepository().addBalance(senderAddress, endowment.negate()); result.getRepository().addBalance(senderAddress, endowment.negate());
result.getRepository().addBalance(newAddress, endowment); result.getRepository().addBalance(newAddress, endowment);
Repository trackRepository = result.getRepository().getTrack(); RepositoryImpl trackRepositoryImpl = result.getRepository().getTrack();
trackRepository.startTracking(); trackRepositoryImpl.startTracking();
// [5] COOK THE INVOKE AND EXECUTE // [5] COOK THE INVOKE AND EXECUTE
ProgramInvoke programInvoke = ProgramInvoke programInvoke =
ProgramInvokeFactory.createProgramInvoke(this, new DataWord(newAddress), DataWord.ZERO, ProgramInvokeFactory.createProgramInvoke(this, new DataWord(newAddress), DataWord.ZERO,
new DataWord(gas), BigInteger.ZERO, null, trackRepository, this.invokeData.getCallDeep() + 1); new DataWord(gas), BigInteger.ZERO, null, trackRepositoryImpl, this.invokeData.getCallDeep() + 1);
VM vm = new VM(); VM vm = new VM();
Program program = new Program(programCode.array(), programInvoke); Program program = new Program(programCode.array(), programInvoke);
@ -300,18 +309,18 @@ public class Program {
result.getException() instanceof Program.OutOfGasException) { result.getException() instanceof Program.OutOfGasException) {
logger.info("contract run halted by OutOfGas: new contract init ={}" , Hex.toHexString(newAddress)); logger.info("contract run halted by OutOfGas: new contract init ={}" , Hex.toHexString(newAddress));
trackRepository.rollback(); trackRepositoryImpl.rollback();
stackPushZero(); stackPushZero();
return; return;
} }
// 4. CREATE THE CONTRACT OUT OF RETURN // 4. CREATE THE CONTRACT OUT OF RETURN
byte[] code = result.getHReturn().array(); byte[] code = result.getHReturn().array();
trackRepository.saveCode(newAddress, code); trackRepositoryImpl.saveCode(newAddress, code);
// IN SUCCESS PUSH THE ADDRESS INTO THE STACK // IN SUCCESS PUSH THE ADDRESS INTO THE STACK
stackPush(new DataWord(newAddress)); stackPush(new DataWord(newAddress));
trackRepository.commit(); trackRepositoryImpl.commit();
// 5. REFUND THE REMAIN GAS // 5. REFUND THE REMAIN GAS
long refundGas = gas - result.getGasUsed(); long refundGas = gas - result.getGasUsed();
@ -388,15 +397,15 @@ public class Program {
// actual gas subtract // actual gas subtract
this.spendGas(gas.intValue(), "internal call"); this.spendGas(gas.intValue(), "internal call");
Repository trackRepository = result.getRepository().getTrack(); RepositoryImpl trackRepositoryImpl = result.getRepository().getTrack();
trackRepository.startTracking(); trackRepositoryImpl.startTracking();
trackRepository.addBalance(toAddress, endowmentValue.value()); trackRepositoryImpl.addBalance(toAddress, endowmentValue.value());
ProgramInvoke programInvoke = ProgramInvoke programInvoke =
ProgramInvokeFactory.createProgramInvoke(this, toAddressDW, ProgramInvokeFactory.createProgramInvoke(this, toAddressDW,
endowmentValue, gas, result.getRepository().getBalance(toAddress), endowmentValue, gas, result.getRepository().getBalance(toAddress),
data.array(), data.array(),
trackRepository, this.invokeData.getCallDeep() + 1); trackRepositoryImpl, this.invokeData.getCallDeep() + 1);
ProgramResult result = null; ProgramResult result = null;
@ -413,7 +422,7 @@ public class Program {
result.getException() instanceof Program.OutOfGasException) { result.getException() instanceof Program.OutOfGasException) {
logger.info("contract run halted by OutOfGas: contract={}" , Hex.toHexString(toAddress)); logger.info("contract run halted by OutOfGas: contract={}" , Hex.toHexString(toAddress));
trackRepository.rollback(); trackRepositoryImpl.rollback();
stackPushZero(); stackPushZero();
return; return;
} }
@ -421,24 +430,20 @@ public class Program {
// 3. APPLY RESULTS: result.getHReturn() into out_memory allocated // 3. APPLY RESULTS: result.getHReturn() into out_memory allocated
if (result != null) { if (result != null) {
ByteBuffer buffer = result.getHReturn(); ByteBuffer buffer = result.getHReturn();
if (buffer != null) { int allocSize = outDataSize.intValue();
int retSize = buffer.array().length; if (buffer != null && allocSize > 0) {
int allocSize = outDataSize.intValue(); int retSize = buffer.limit();
int offset = outDataOffs.intValue();
if (retSize > allocSize) { if (retSize > allocSize) {
byte[] outArray = Arrays.copyOf(buffer.array(), allocSize); this.memorySave(offset, buffer.array());
this.memorySave(outArray, buffer.array());
} else if (retSize == 0 || retSize == allocSize){
this.memorySave(outDataOffs.getData(), buffer.array());
} else { } else {
byte[] outArray = new byte[allocSize]; this.memorySave(offset, allocSize, buffer.array());
System.arraycopy(buffer.array(), 0, outArray, 0, retSize);
this.memorySave(outDataOffs.getData(), outArray);
} }
} }
} }
// 4. THE FLAG OF SUCCESS IS ONE PUSHED INTO THE STACK // 4. THE FLAG OF SUCCESS IS ONE PUSHED INTO THE STACK
trackRepository.commit(); trackRepositoryImpl.commit();
stackPushOne(); stackPushOne();
// 5. REFUND THE REMAIN GAS // 5. REFUND THE REMAIN GAS
@ -702,4 +707,4 @@ public class Program {
@SuppressWarnings("serial") @SuppressWarnings("serial")
public class OutOfGasException extends RuntimeException { public class OutOfGasException extends RuntimeException {
} }
} }

View File

@ -1,6 +1,6 @@
package org.ethereum.vm; package org.ethereum.vm;
import org.ethereum.db.Repository; import org.ethereum.db.RepositoryImpl;
/** /**
* www.ethereumJ.com * www.ethereumJ.com
@ -27,7 +27,7 @@ public interface ProgramInvoke {
public DataWord getDifficulty(); public DataWord getDifficulty();
public DataWord getGaslimit(); public DataWord getGaslimit();
public Repository getRepository(); public RepositoryImpl getRepository();
public boolean byTransaction(); public boolean byTransaction();
boolean byTestingSuite(); boolean byTestingSuite();

View File

@ -2,7 +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.Repository; import org.ethereum.db.RepositoryImpl;
import org.ethereum.manager.WorldManager; import org.ethereum.manager.WorldManager;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -21,7 +21,7 @@ public class ProgramInvokeFactory {
private static Logger logger = LoggerFactory.getLogger("VM"); private static Logger logger = LoggerFactory.getLogger("VM");
// Invocation by the wire tx // Invocation by the wire tx
public static ProgramInvoke createProgramInvoke(Transaction tx, Block block, Repository repository) { public static ProgramInvoke createProgramInvoke(Transaction tx, Block block, RepositoryImpl repository) {
// https://ethereum.etherpad.mozilla.org/26 // https://ethereum.etherpad.mozilla.org/26
Block lastBlock = WorldManager.getInstance().getBlockchain().getLastBlock(); Block lastBlock = WorldManager.getInstance().getBlockchain().getLastBlock();
@ -122,7 +122,7 @@ public class ProgramInvokeFactory {
public static ProgramInvoke createProgramInvoke(Program program, DataWord toAddress, public static ProgramInvoke createProgramInvoke(Program program, DataWord toAddress,
DataWord inValue, DataWord inGas, DataWord inValue, DataWord inGas,
BigInteger balanceInt, byte[] dataIn, BigInteger balanceInt, byte[] dataIn,
Repository repository, int callDeep) { RepositoryImpl repository, int callDeep) {
DataWord address = toAddress; DataWord address = toAddress;
DataWord origin = program.getOriginAddress(); DataWord origin = program.getOriginAddress();

View File

@ -1,6 +1,6 @@
package org.ethereum.vm; package org.ethereum.vm;
import org.ethereum.db.Repository; import org.ethereum.db.RepositoryImpl;
import java.math.BigInteger; import java.math.BigInteger;
import java.util.Arrays; import java.util.Arrays;
@ -26,7 +26,7 @@ public class ProgramInvokeImpl implements ProgramInvoke {
Map<DataWord, DataWord> storage; Map<DataWord, DataWord> storage;
private Repository repository; private RepositoryImpl repository;
private boolean byTransaction = true; private boolean byTransaction = true;
private boolean byTestingSuite = false; private boolean byTestingSuite = false;
private int callDeep = 0; private int callDeep = 0;
@ -34,7 +34,7 @@ public class ProgramInvokeImpl implements ProgramInvoke {
public ProgramInvokeImpl(DataWord address, DataWord origin, DataWord caller, DataWord balance, public ProgramInvokeImpl(DataWord address, DataWord origin, DataWord caller, DataWord balance,
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 difficulty, DataWord lastHash, DataWord coinbase, DataWord timestamp, DataWord number, DataWord difficulty,
DataWord gaslimit, Repository repository, int callDeep) { DataWord gaslimit, RepositoryImpl repository, int callDeep) {
// Transaction env // Transaction env
this.address = address; this.address = address;
@ -63,7 +63,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, boolean byTestingSuite) { RepositoryImpl repository, 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);
this.byTestingSuite = byTestingSuite; this.byTestingSuite = byTestingSuite;
@ -74,7 +74,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) { RepositoryImpl repository) {
// Transaction env // Transaction env
this.address = new DataWord(address); this.address = new DataWord(address);
@ -215,7 +215,7 @@ public class ProgramInvokeImpl implements ProgramInvoke {
/* Storage */ /* Storage */
public Map<DataWord, DataWord> getStorage() { return storage; } public Map<DataWord, DataWord> getStorage() { return storage; }
public Repository getRepository() { public RepositoryImpl getRepository() {
return repository; return repository;
} }

View File

@ -2,7 +2,7 @@ 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.Repository; import org.ethereum.db.RepositoryImpl;
import org.spongycastle.util.encoders.Hex; import org.spongycastle.util.encoders.Hex;
/** /**
@ -15,7 +15,7 @@ public class ProgramInvokeMockImpl implements ProgramInvoke {
private byte[] msgData; private byte[] msgData;
private Repository repository = null; private RepositoryImpl repository = null;
private String ownerAddress = "cd2a3d9f938e13cd947ec05abc7fe734df8dd826"; private String ownerAddress = "cd2a3d9f938e13cd947ec05abc7fe734df8dd826";
public ProgramInvokeMockImpl(byte[] msgDataRaw) { public ProgramInvokeMockImpl(byte[] msgDataRaw) {
@ -24,7 +24,7 @@ public class ProgramInvokeMockImpl implements ProgramInvoke {
} }
public ProgramInvokeMockImpl() { public ProgramInvokeMockImpl() {
this.repository = new Repository(); this.repository = new RepositoryImpl();
this.repository.createAccount(Hex.decode(ownerAddress)); this.repository.createAccount(Hex.decode(ownerAddress));
} }
@ -179,11 +179,11 @@ public class ProgramInvokeMockImpl implements ProgramInvoke {
} }
@Override @Override
public Repository getRepository() { public RepositoryImpl getRepository() {
return this.repository; return this.repository;
} }
public void setRepository(Repository repository) { public void setRepository(RepositoryImpl repository) {
this.repository = repository; this.repository = repository;
} }

View File

@ -1,6 +1,6 @@
package org.ethereum.vm; package org.ethereum.vm;
import org.ethereum.db.Repository; import org.ethereum.db.RepositoryImpl;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.util.ArrayList; import java.util.ArrayList;
@ -18,7 +18,7 @@ public class ProgramResult {
private RuntimeException exception; private RuntimeException exception;
private List<DataWord> deleteAccounts; private List<DataWord> deleteAccounts;
private Repository repository = null; private RepositoryImpl repository = null;
/* /*
* for testing runs , * for testing runs ,
@ -55,11 +55,11 @@ public class ProgramResult {
this.exception = exception; this.exception = exception;
} }
public Repository getRepository() { public RepositoryImpl getRepository() {
return repository; return repository;
} }
public void setRepository(Repository repository) { public void setRepository(RepositoryImpl repository) {
this.repository = repository; this.repository = repository;
} }

View File

@ -144,8 +144,8 @@ public class VM {
} }
callGas = callGasWord.longValue(); callGas = callGasWord.longValue();
// Casting to long (causing overflow) as workaround for PoC5 - should be removed for PoC6 // Casting to long (causing overflow) as workaround for PoC5 - should be removed for PoC6
long x = stack.get(stack.size()-6).value().add(stack.get(stack.size()-7).value()).longValue(); long x = stack.get(stack.size()-4).value().add(stack.get(stack.size()-5).value()).longValue(); // in offset+size
long y = stack.get(stack.size()-4).value().add(stack.get(stack.size()-5).value()).longValue(); long y = stack.get(stack.size()-6).value().add(stack.get(stack.size()-7).value()).longValue(); // out offset+size
newMemSize = BigInteger.valueOf(Math.max(x, y)); newMemSize = BigInteger.valueOf(Math.max(x, y));
break; break;
case CREATE: case CREATE:
@ -157,6 +157,7 @@ public class VM {
} }
program.spendGas(gasCost, op.name()); program.spendGas(gasCost, op.name());
// Avoid overflows
if(newMemSize.compareTo(MAX_GAS) == 1) { if(newMemSize.compareTo(MAX_GAS) == 1) {
throw program.new OutOfGasException(); throw program.new OutOfGasException();
} }
@ -422,7 +423,7 @@ public class VM {
DataWord word2 = program.stackPop(); DataWord word2 = program.stackPop();
DataWord result = null; DataWord result = null;
if (word1.value().compareTo(_32_) == -1) { if (word1.value().compareTo(_32_) == -1) {
byte tmp = word2.getData()[word1.value().intValue()]; byte tmp = word2.getData()[word1.intValue()];
word2.and(DataWord.ZERO); word2.and(DataWord.ZERO);
word2.getData()[31] = tmp; word2.getData()[31] = tmp;
result = word2; result = word2;
@ -535,7 +536,7 @@ public class VM {
if (logger.isInfoEnabled()) if (logger.isInfoEnabled())
hint = "data: " + Hex.toHexString(msgData); hint = "data: " + Hex.toHexString(msgData);
program.memorySave(memOffsetData.getData(), msgData); program.memorySave(memOffsetData.intValue(), msgData);
program.step(); program.step();
} break; } break;
case CODESIZE:{ case CODESIZE:{
@ -552,8 +553,8 @@ public class VM {
DataWord codeOffsetData = program.stackPop(); DataWord codeOffsetData = program.stackPop();
DataWord lengthData = program.stackPop(); DataWord lengthData = program.stackPop();
int length = lengthData.value().intValue(); int length = lengthData.intValue();
int codeOffset = codeOffsetData.value().intValue(); int codeOffset = codeOffsetData.intValue();
if (program.ops.length < length + codeOffset) { if (program.ops.length < length + codeOffset) {
program.stop(); program.stop();
@ -566,7 +567,7 @@ public class VM {
if (logger.isInfoEnabled()) if (logger.isInfoEnabled())
hint = "code: " + Hex.toHexString(code); hint = "code: " + Hex.toHexString(code);
program.memorySave(memOffsetData.getData(), code); program.memorySave(memOffsetData.intValue(), code);
program.step(); program.step();
} break; } break;
case GASPRICE:{ case GASPRICE:{
@ -678,7 +679,7 @@ public class VM {
DataWord addr = program.stackPop(); DataWord addr = program.stackPop();
DataWord value = program.stackPop(); DataWord value = program.stackPop();
byte[] byteVal = {value.getData()[31]}; byte[] byteVal = {value.getData()[31]};
program.memorySave(addr.getData(), byteVal); program.memorySave(addr.intValue(), byteVal);
program.step(); program.step();
} break; } break;
case SLOAD:{ case SLOAD:{
@ -938,4 +939,4 @@ public class VM {
@SuppressWarnings("serial") @SuppressWarnings("serial")
private class IllegalOperationException extends RuntimeException {} private class IllegalOperationException extends RuntimeException {}
} }

View File

@ -2,7 +2,7 @@ package org.ethereum.core;
import org.ethereum.crypto.ECKey; import org.ethereum.crypto.ECKey;
import org.ethereum.crypto.HashUtil; import org.ethereum.crypto.HashUtil;
import org.ethereum.db.Repository; import org.ethereum.db.RepositoryImpl;
import org.ethereum.manager.WorldManager; import org.ethereum.manager.WorldManager;
import org.junit.*; import org.junit.*;
import org.junit.runners.MethodSorters; import org.junit.runners.MethodSorters;
@ -37,7 +37,7 @@ public class WalletTest {
@Test // Testing account for simple balance set @Test // Testing account for simple balance set
public void accountTest_1(){ public void accountTest_1(){
Repository repository = WorldManager.getInstance().getRepository(); RepositoryImpl repository = WorldManager.getInstance().getRepository();
ECKey cowKey = ECKey.fromPrivate(HashUtil.sha3("cow".getBytes())); ECKey cowKey = ECKey.fromPrivate(HashUtil.sha3("cow".getBytes()));
repository.createAccount(cowKey.getAddress()); repository.createAccount(cowKey.getAddress());
@ -55,7 +55,7 @@ public class WalletTest {
@Test // test account balance with pending "unblocked" transaction @Test // test account balance with pending "unblocked" transaction
public void accountTest_2(){ public void accountTest_2(){
Repository repository = WorldManager.getInstance().getRepository(); RepositoryImpl repository = WorldManager.getInstance().getRepository();
ECKey cowKey = ECKey.fromPrivate(HashUtil.sha3("cow".getBytes())); ECKey cowKey = ECKey.fromPrivate(HashUtil.sha3("cow".getBytes()));
repository.createAccount(cowKey.getAddress()); repository.createAccount(cowKey.getAddress());

View File

@ -23,7 +23,7 @@ public class RepositoryTest {
public void test1() { public void test1() {
String addr = "cd2a3d9f938e13cd947ec05abc7fe734df8dd826"; String addr = "cd2a3d9f938e13cd947ec05abc7fe734df8dd826";
Repository repository = new Repository(); RepositoryImpl repository = new RepositoryImpl();
try { try {
AccountState createdState = repository.createAccount(Hex.decode(addr)); AccountState createdState = repository.createAccount(Hex.decode(addr));
@ -38,7 +38,7 @@ public class RepositoryTest {
public void test2() { public void test2() {
String addr = "cd2a3d9f938e13cd947ec05abc7fe734df8dd826"; String addr = "cd2a3d9f938e13cd947ec05abc7fe734df8dd826";
Repository repository = new Repository(); RepositoryImpl repository = new RepositoryImpl();
try { try {
BigInteger nonce0 = repository.getNonce(Hex.decode(addr)); BigInteger nonce0 = repository.getNonce(Hex.decode(addr));
@ -61,7 +61,7 @@ public class RepositoryTest {
public void test3() { public void test3() {
String addr = "cd2a3d9f938e13cd947ec05abc7fe734df8dd826"; String addr = "cd2a3d9f938e13cd947ec05abc7fe734df8dd826";
Repository repository = new Repository(); RepositoryImpl repository = new RepositoryImpl();
try { try {
BigInteger nonce0 = repository.getNonce(Hex.decode(addr)); BigInteger nonce0 = repository.getNonce(Hex.decode(addr));
@ -85,7 +85,7 @@ public class RepositoryTest {
public void test4() { public void test4() {
String addr = "cd2a3d9f938e13cd947ec05abc7fe734df8dd826"; String addr = "cd2a3d9f938e13cd947ec05abc7fe734df8dd826";
Repository repository = new Repository(); RepositoryImpl repository = new RepositoryImpl();
try { try {
BigInteger balance0 = repository.getBalance(Hex.decode(addr)); BigInteger balance0 = repository.getBalance(Hex.decode(addr));
@ -107,7 +107,7 @@ public class RepositoryTest {
public void test5() { public void test5() {
String addr = "cd2a3d9f938e13cd947ec05abc7fe734df8dd826"; String addr = "cd2a3d9f938e13cd947ec05abc7fe734df8dd826";
Repository repository = new Repository(); RepositoryImpl repository = new RepositoryImpl();
try { try {
BigInteger balance0 = repository.getBalance(Hex.decode(addr)); BigInteger balance0 = repository.getBalance(Hex.decode(addr));
@ -133,7 +133,7 @@ public class RepositoryTest {
public void test6() { public void test6() {
String addr = "cd2a3d9f938e13cd947ec05abc7fe734df8dd826"; String addr = "cd2a3d9f938e13cd947ec05abc7fe734df8dd826";
Repository repository = new Repository(); RepositoryImpl repository = new RepositoryImpl();
byte[] code; byte[] code;
try { try {
@ -151,7 +151,7 @@ public class RepositoryTest {
String codeString = "7f60c860005461012c602054000000000000000000000000000000000000000000600060206000f200"; String codeString = "7f60c860005461012c602054000000000000000000000000000000000000000000600060206000f200";
String codeHash = "8f0d7fc8cc6fdd688fa58ae9256310069f5659ed2a8a3af994d80350fbf1e798"; String codeHash = "8f0d7fc8cc6fdd688fa58ae9256310069f5659ed2a8a3af994d80350fbf1e798";
Repository repository = new Repository(); RepositoryImpl repository = new RepositoryImpl();
try { try {
byte[] code0 = repository.getCode(Hex.decode(addr)); byte[] code0 = repository.getCode(Hex.decode(addr));
@ -174,7 +174,7 @@ public class RepositoryTest {
String addr = "cd2a3d9f938e13cd947ec05abc7fe734df8dd826"; String addr = "cd2a3d9f938e13cd947ec05abc7fe734df8dd826";
String codeHash = "c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470"; String codeHash = "c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470";
Repository repository = new Repository(); RepositoryImpl repository = new RepositoryImpl();
try { try {
byte[] code0 = repository.getCode(Hex.decode(addr)); byte[] code0 = repository.getCode(Hex.decode(addr));
@ -197,7 +197,7 @@ public class RepositoryTest {
byte[] keyBytes = Hex.decode("c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470"); byte[] keyBytes = Hex.decode("c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470");
DataWord key = new DataWord(keyBytes); DataWord key = new DataWord(keyBytes);
Repository repository = new Repository(); RepositoryImpl repository = new RepositoryImpl();
try { try {
DataWord value = repository.getStorageValue(Hex.decode(addr), key); DataWord value = repository.getStorageValue(Hex.decode(addr), key);
@ -211,7 +211,7 @@ public class RepositoryTest {
public void test10() { public void test10() {
String addr = "cd2a3d9f938e13cd947ec05abc7fe734df8dd826"; String addr = "cd2a3d9f938e13cd947ec05abc7fe734df8dd826";
Repository repository = new Repository(); RepositoryImpl repository = new RepositoryImpl();
try { try {
repository.createAccount(Hex.decode(addr)); repository.createAccount(Hex.decode(addr));
@ -233,7 +233,7 @@ public class RepositoryTest {
String addr = "cd2a3d9f938e13cd947ec05abc7fe734df8dd826"; String addr = "cd2a3d9f938e13cd947ec05abc7fe734df8dd826";
String expectedStorageHash = "a737c40a4aa895fb9eb464536c376ee7c2c08eb733c8fd2353fcc62dc734f075"; String expectedStorageHash = "a737c40a4aa895fb9eb464536c376ee7c2c08eb733c8fd2353fcc62dc734f075";
Repository repository = new Repository(); RepositoryImpl repository = new RepositoryImpl();
try { try {
repository.createAccount(Hex.decode(addr)); repository.createAccount(Hex.decode(addr));
@ -283,10 +283,10 @@ public class RepositoryTest {
String expectedStorageHash = "365ed874ad42c2b4af335212465291e03dcd1f0c5b600f40f048ed238ad61fd3"; String expectedStorageHash = "365ed874ad42c2b4af335212465291e03dcd1f0c5b600f40f048ed238ad61fd3";
long expectedBalance = 333; long expectedBalance = 333;
Repository origRepository = new Repository(); RepositoryImpl origRepository = new RepositoryImpl();
try { try {
Repository repository = origRepository.getTrack(); RepositoryImpl repository = origRepository.getTrack();
repository.startTracking(); repository.startTracking();
repository.createAccount(Hex.decode(addr)); repository.createAccount(Hex.decode(addr));
@ -310,8 +310,8 @@ public class RepositoryTest {
long expectedBalance_1 = 55500; long expectedBalance_1 = 55500;
long expectedBalance_2 = 0; long expectedBalance_2 = 0;
Repository origRepository = new Repository(); RepositoryImpl origRepository = new RepositoryImpl();
Repository repository = origRepository.getTrack(); RepositoryImpl repository = origRepository.getTrack();
repository.startTracking(); repository.startTracking();
repository.createAccount(Hex.decode(addr)); repository.createAccount(Hex.decode(addr));
@ -336,8 +336,8 @@ public class RepositoryTest {
long expectedBalance = 55500; long expectedBalance = 55500;
Repository origRepository = new Repository(); RepositoryImpl origRepository = new RepositoryImpl();
Repository repository = origRepository.getTrack(); RepositoryImpl repository = origRepository.getTrack();
try { try {
repository.createAccount(Hex.decode(addr_1)); repository.createAccount(Hex.decode(addr_1));

View File

@ -15,7 +15,7 @@ import static org.junit.Assert.assertEquals;
public class UtilsTest { public class UtilsTest {
@Test @Test
public void getValueShortString1() { public void testGetValueShortString1() {
String expected = "123·(10^24)"; String expected = "123·(10^24)";
String result = Utils.getValueShortString(new BigInteger("123456789123445654363653463")); String result = Utils.getValueShortString(new BigInteger("123456789123445654363653463"));
@ -24,7 +24,7 @@ public class UtilsTest {
} }
@Test @Test
public void getValueShortString2() { public void testGetValueShortString2() {
String expected = "123·(10^3)"; String expected = "123·(10^3)";
String result = Utils.getValueShortString(new BigInteger("123456")); String result = Utils.getValueShortString(new BigInteger("123456"));
@ -33,7 +33,7 @@ public class UtilsTest {
} }
@Test @Test
public void getValueShortString3() { public void testGetValueShortString3() {
String expected = "1·(10^3)"; String expected = "1·(10^3)";
String result = Utils.getValueShortString(new BigInteger("1234")); String result = Utils.getValueShortString(new BigInteger("1234"));
@ -42,7 +42,7 @@ public class UtilsTest {
} }
@Test @Test
public void getValueShortString4() { public void testGetValueShortString4() {
String expected = "123·(10^0)"; String expected = "123·(10^0)";
String result = Utils.getValueShortString(new BigInteger("123")); String result = Utils.getValueShortString(new BigInteger("123"));
@ -51,7 +51,7 @@ public class UtilsTest {
} }
@Test @Test
public void getValueShortString5() { public void testGetValueShortString5() {
byte[] decimal = Hex.decode("3913517ebd3c0c65000000"); byte[] decimal = Hex.decode("3913517ebd3c0c65000000");
String expected = "69·(10^24)"; String expected = "69·(10^24)";
@ -59,4 +59,4 @@ public class UtilsTest {
assertEquals(expected, result); assertEquals(expected, result);
} }
} }

View File

@ -0,0 +1,335 @@
package org.ethereum.vm;
import static org.junit.Assert.*;
import java.nio.ByteBuffer;
import org.ethereum.util.ByteUtil;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
public class ProgramMemoryTest {
ProgramInvokeMockImpl pi = null;
Program program;
ByteBuffer memory;
@Before
public void createProgram() {
program = new Program(ByteUtil.EMPTY_BYTE_ARRAY, pi);
}
@Test
public void testGetMemSize() {
ByteBuffer memory = ByteBuffer.allocate(64);
program.memory = memory;
assertEquals(64, program.getMemSize());
}
@Test
@Ignore
public void testMemorySave() {
fail("Not yet implemented");
}
@Test
@Ignore
public void testMemoryLoad() {
fail("Not yet implemented");
}
@Test
@Ignore
public void testMemoryChunk() {
fail("Not yet implemented");
}
@Test
public void testAllocateMemory1() {
memory = ByteBuffer.allocate(64);
int offset = 32;
int size = 32;
program.memory = memory;
program.allocateMemory(offset, size);
assertEquals(64, program.getMemSize());
}
@Test
public void testAllocateMemory2() {
// memory.limit() > offset, == size
// memory.limit() < offset + size
memory = ByteBuffer.allocate(64);
int offset = 32;
int size = 64;
program.memory = memory;
program.allocateMemory(offset, size);
assertEquals(96, program.getMemSize());
}
@Test
public void testAllocateMemory3() {
// memory.limit() > offset, > size
memory = ByteBuffer.allocate(64);
int offset = 0;
int size = 32;
program.memory = memory;
program.allocateMemory(offset, size);
assertEquals(64, program.getMemSize());
}
@Test
public void testAllocateMemory4() {
memory = ByteBuffer.allocate(64);;
int offset = 0;
int size = 64;
program.memory = memory;
program.allocateMemory(offset, size);
assertEquals(64, program.getMemSize());
}
@Test
public void testAllocateMemory5() {
memory = ByteBuffer.allocate(64);
int offset = 0;
int size = 0;
program.memory = memory;
program.allocateMemory(offset, size);
assertEquals(64, program.getMemSize());
}
@Test
public void testAllocateMemory6() {
// memory.limit() == offset, > size
memory = ByteBuffer.allocate(64);
int offset = 64;
int size = 32;
program.memory = memory;
program.allocateMemory(offset, size);
assertEquals(96, program.getMemSize());
}
@Test
public void testAllocateMemory7() {
// memory.limit() == offset - size
memory = ByteBuffer.allocate(64);
int offset = 96;
int size = 32;
program.memory = memory;
program.allocateMemory(offset, size);
assertEquals(128, program.getMemSize());
}
@Test
public void testAllocateMemory8() {
memory = ByteBuffer.allocate(64);
int offset = 0;
int size = 96;
program.memory = memory;
program.allocateMemory(offset, size);
assertEquals(96, program.getMemSize());
}
@Test
public void testAllocateMemory9() {
// memory.limit() < offset, > size
// memory.limit() < offset - size
memory = ByteBuffer.allocate(64);
int offset = 96;
int size = 0;
program.memory = memory;
program.allocateMemory(offset, size);
assertEquals(96, program.getMemSize());
}
/************************************************/
@Test
public void testAllocateMemory10() {
// memory = null, offset > size
int offset = 32;
int size = 0;
program.memory = memory;
program.allocateMemory(offset, size);
assertEquals(32, program.getMemSize());
}
@Test
public void testAllocateMemory11() {
// memory = null, offset < size
int offset = 0;
int size = 32;
program.memory = memory;
program.allocateMemory(offset, size);
assertEquals(32, program.getMemSize());
}
@Test
public void testAllocateMemory12() {
// memory.limit() < offset, < size
memory = ByteBuffer.allocate(32);
int offset = 64;
int size = 96;
program.memory = memory;
program.allocateMemory(offset, size);
assertEquals(160, program.getMemSize());
}
@Test
public void testAllocateMemory13() {
// memory.limit() > offset, < size
memory = ByteBuffer.allocate(64);
int offset = 32;
int size = 128;
program.memory = memory;
program.allocateMemory(offset, size);
assertEquals(160, program.getMemSize());
}
@Test
public void testAllocateMemory14() {
// memory.limit() < offset, == size
memory = ByteBuffer.allocate(64);
int offset = 96;
int size = 64;
program.memory = memory;
program.allocateMemory(offset, size);
assertEquals(160, program.getMemSize());
}
@Test
public void testAllocateMemory15() {
// memory.limit() == offset, < size
memory = ByteBuffer.allocate(64);
int offset = 64;
int size = 96;
program.memory = memory;
program.allocateMemory(offset, size);
assertEquals(160, program.getMemSize());
}
@Test
public void testAllocateMemory16() {
// memory.limit() == offset, == size
// memory.limit() > offset - size
memory = ByteBuffer.allocate(64);
int offset = 64;
int size = 64;
program.memory = memory;
program.allocateMemory(offset, size);
assertEquals(128, program.getMemSize());
}
@Test
public void testAllocateMemory17() {
// memory.limit() > offset + size
memory = ByteBuffer.allocate(96);
int offset = 32;
int size = 32;
program.memory = memory;
program.allocateMemory(offset, size);
assertEquals(96, program.getMemSize());
}
@Test
public void testAllocateMemoryUnrounded1() {
// memory unrounded
memory = ByteBuffer.allocate(16);
int offset = 64;
int size = 32;
program.memory = memory;
program.allocateMemory(offset, size);
assertEquals(96, program.getMemSize());
}
@Test
public void testAllocateMemoryUnrounded2() {
// offset unrounded
memory = ByteBuffer.allocate(32);
int offset = 16;
int size = 32;
program.memory = memory;
program.allocateMemory(offset, size);
assertEquals(64, program.getMemSize());
}
@Test
public void testAllocateMemoryUnrounded3() {
// size unrounded
memory = ByteBuffer.allocate(32);
int offset = 64;
int size = 16;
program.memory = memory;
program.allocateMemory(offset, size);
assertEquals(96, program.getMemSize());
}
@Test
public void testAllocateMemoryUnrounded4() {
// memory + offset unrounded
memory = ByteBuffer.allocate(16);
int offset = 16;
int size = 32;
program.memory = memory;
program.allocateMemory(offset, size);
assertEquals(64 , program.getMemSize());
}
@Test
public void testAllocateMemoryUnrounded5() {
// memory + size unrounded
memory = ByteBuffer.allocate(16);
int offset = 32;
int size = 16;
program.memory = memory;
program.allocateMemory(offset, size);
assertEquals(64, program.getMemSize());
}
@Test
public void testAllocateMemoryUnrounded6() {
// offset + size unrounded
memory = ByteBuffer.allocate(32);
int offset = 16;
int size = 16;
program.memory = memory;
program.allocateMemory(offset, size);
assertEquals(32, program.getMemSize());
}
@Test
public void testAllocateMemoryUnrounded7() {
// memory + offset + size unrounded
memory = ByteBuffer.allocate(16);
int offset = 16;
int size = 16;
program.memory = memory;
program.allocateMemory(offset, size);
assertEquals(32,program.getMemSize());
}
}

View File

@ -2,7 +2,7 @@ package org.ethereum.vm;
import org.ethereum.core.AccountState; import org.ethereum.core.AccountState;
import org.ethereum.crypto.HashUtil; import org.ethereum.crypto.HashUtil;
import org.ethereum.db.Repository; import org.ethereum.db.RepositoryImpl;
import org.junit.FixMethodOrder; import org.junit.FixMethodOrder;
import org.junit.Ignore; import org.junit.Ignore;
import org.junit.Test; import org.junit.Test;
@ -59,7 +59,7 @@ public class VMComplexTest {
ProgramInvokeMockImpl pi = new ProgramInvokeMockImpl(); ProgramInvokeMockImpl pi = new ProgramInvokeMockImpl();
pi.setOwnerAddress("77045e71a7a2c50903d88e564cd72fab11e82051"); pi.setOwnerAddress("77045e71a7a2c50903d88e564cd72fab11e82051");
Repository repository = pi.getRepository(); RepositoryImpl repository = pi.getRepository();
repository.createAccount(callerAddrB); repository.createAccount(callerAddrB);
repository.addBalance(callerAddrB, new BigInteger("100000000000000000000")); repository.addBalance(callerAddrB, new BigInteger("100000000000000000000"));
@ -134,7 +134,7 @@ public class VMComplexTest {
ProgramInvokeMockImpl pi = new ProgramInvokeMockImpl(); ProgramInvokeMockImpl pi = new ProgramInvokeMockImpl();
pi.setOwnerAddress(contractB_addr); pi.setOwnerAddress(contractB_addr);
Repository repository = pi.getRepository(); RepositoryImpl repository = pi.getRepository();
byte[] contractB_addr_bytes = Hex.decode(contractB_addr); byte[] contractB_addr_bytes = Hex.decode(contractB_addr);
byte[] codeB = Hex.decode(code_b); byte[] codeB = Hex.decode(code_b);
@ -234,7 +234,7 @@ public class VMComplexTest {
ProgramInvokeMockImpl pi = new ProgramInvokeMockImpl(); ProgramInvokeMockImpl pi = new ProgramInvokeMockImpl();
pi.setOwnerAddress(contractB_addr); pi.setOwnerAddress(contractB_addr);
Repository repository = pi.getRepository(); RepositoryImpl repository = pi.getRepository();
repository.createAccount(contractA_addr_bytes); repository.createAccount(contractA_addr_bytes);
repository.saveCode(contractA_addr_bytes, codeA); repository.saveCode(contractA_addr_bytes, codeA);
@ -315,7 +315,7 @@ public class VMComplexTest {
ProgramInvokeMockImpl pi = new ProgramInvokeMockImpl(); ProgramInvokeMockImpl pi = new ProgramInvokeMockImpl();
pi.setOwnerAddress(contractA_addr); pi.setOwnerAddress(contractA_addr);
Repository repository = pi.getRepository(); RepositoryImpl repository = pi.getRepository();
byte[] caller_addr_bytes = Hex.decode(callerAddr); byte[] caller_addr_bytes = Hex.decode(callerAddr);

View File

@ -1,6 +1,6 @@
package org.ethereum.vm; package org.ethereum.vm;
import org.ethereum.db.Repository; import org.ethereum.db.RepositoryImpl;
import org.ethereum.vm.Program.OutOfGasException; import org.ethereum.vm.Program.OutOfGasException;
import org.junit.FixMethodOrder; import org.junit.FixMethodOrder;
import org.junit.Test; import org.junit.Test;
@ -1540,7 +1540,7 @@ public class VMTest {
vm.step(program); vm.step(program);
vm.step(program); vm.step(program);
Repository repository = program.result.getRepository(); RepositoryImpl repository = program.result.getRepository();
DataWord key = new DataWord(Hex.decode(s_expected_key)); DataWord key = new DataWord(Hex.decode(s_expected_key));
DataWord val = repository.getStorageValue(invoke.getOwnerAddress().getNoLeadZeroesData(), key); DataWord val = repository.getStorageValue(invoke.getOwnerAddress().getNoLeadZeroesData(), key);

View File

@ -2,7 +2,7 @@ package org.ethereum.gui;
import org.ethereum.core.Block; import org.ethereum.core.Block;
import org.ethereum.core.Transaction; import org.ethereum.core.Transaction;
import org.ethereum.db.Repository; import org.ethereum.db.RepositoryImpl;
import org.ethereum.manager.WorldManager; import org.ethereum.manager.WorldManager;
import org.ethereum.vm.*; import org.ethereum.vm.*;
import org.spongycastle.util.encoders.Hex; import org.spongycastle.util.encoders.Hex;
@ -49,7 +49,7 @@ public class ProgramPlayDialog extends JPanel implements ActionListener,
outputList = new ArrayList<String>(); outputList = new ArrayList<String>();
VM vm = new VM(); VM vm = new VM();
Repository tractRepository = WorldManager.getInstance().getRepository().getTrack(); RepositoryImpl tractRepository = WorldManager.getInstance().getRepository().getTrack();
Program program = new Program(code , Program program = new Program(code ,
ProgramInvokeFactory.createProgramInvoke(tx, lastBlock, tractRepository)); ProgramInvokeFactory.createProgramInvoke(tx, lastBlock, tractRepository));