Repository redesign:

+ clean and structured design of the tracker
+ batch write to the db at end of the process
+ record blocks for runnable test scenario
This commit is contained in:
romanman 2014-11-19 12:46:28 -05:00
parent 187fcef1c4
commit 8bf61332ae
30 changed files with 2760 additions and 822 deletions

View File

@ -18,7 +18,7 @@ import org.springframework.stereotype.Component;
*/
public class SystemProperties {
private static Logger logger = LoggerFactory.getLogger(SystemProperties.class);
private static Logger logger = LoggerFactory.getLogger("general");
private static int DEFAULT_TX_APPROVE_TIMEOUT = 10;
private static String DEFAULT_DISCOVERY_PEER_LIST = "poc-7.ethdev.com:30303";
@ -29,6 +29,7 @@ public class SystemProperties {
private static int DEFAULT_ACTIVE_PEER_CHANNEL_TIMEOUT = 5;
private static Boolean DEFAULT_DB_RESET = false;
private static Boolean DEFAULT_DUMP_FULL = false;
private static Boolean DEFAULT_RECORD_BLOCKS = false;
private static String DEFAULT_DUMP_DIR = "dmp";
private static String DEFAULT_DUMP_STYLE = "standard+";
private static Integer DEFAULT_VMTRACE_BLOCK = 0;
@ -61,6 +62,7 @@ public class SystemProperties {
File file = new File(fileName);
if (file.exists()) {
logger.info("config loaded from {}", fileName);
input = new FileInputStream(file);
} else {
fileName = "system.properties";
@ -159,6 +161,12 @@ public class SystemProperties {
return Integer.parseInt(prop.getProperty("trace.startblock"));
}
public Boolean recordBlocks() {
if (prop.isEmpty()) return DEFAULT_RECORD_BLOCKS;
return Boolean.parseBoolean(prop.getProperty("record.blocks"));
}
public Boolean dumpFull() {
if (prop.isEmpty()) return DEFAULT_DUMP_FULL;
return Boolean.parseBoolean(prop.getProperty("dump.full"));

View File

@ -1,14 +1,14 @@
package org.ethereum.core;
import static org.ethereum.crypto.HashUtil.EMPTY_DATA_HASH;
import static org.ethereum.crypto.HashUtil.EMPTY_TRIE_HASH;
import org.ethereum.util.RLP;
import org.ethereum.util.RLPList;
import org.spongycastle.util.encoders.Hex;
import java.math.BigInteger;
import static org.ethereum.crypto.HashUtil.EMPTY_DATA_HASH;
import static org.ethereum.crypto.HashUtil.EMPTY_TRIE_HASH;
public class AccountState {
private byte[] rlpEncoded;
@ -41,6 +41,10 @@ public class AccountState {
* retrieval */
private byte[] codeHash = EMPTY_DATA_HASH;
private boolean dirty = false;
private boolean deleted = false;
public AccountState() {
this(BigInteger.ZERO, BigInteger.ZERO);
}
@ -66,6 +70,10 @@ public class AccountState {
return nonce;
}
public void setNonce(BigInteger nonce) {
this.nonce = nonce;
}
public byte[] getStateRoot() {
return stateRoot;
}
@ -73,11 +81,13 @@ public class AccountState {
public void setStateRoot(byte[] stateRoot) {
rlpEncoded = null;
this.stateRoot = stateRoot;
setDirty(true);
}
public void incrementNonce() {
rlpEncoded = null;
this.nonce = nonce.add(BigInteger.ONE);
setDirty(true);
}
public byte[] getCodeHash() {
@ -96,12 +106,14 @@ public class AccountState {
public BigInteger addToBalance(BigInteger value) {
if (value.signum() != 0) rlpEncoded = null;
this.balance = balance.add(value);
setDirty(true);
return this.balance;
}
public void subFromBalance(BigInteger value) {
if (value.signum() != 0) rlpEncoded = null;
this.balance = balance.subtract(value);
setDirty(true);
}
public byte[] getEncoded() {
@ -114,7 +126,34 @@ public class AccountState {
}
return rlpEncoded;
}
public void setDirty(boolean dirty) {
this.dirty = dirty;
}
public void setDeleted(boolean deleted) {
this.deleted = deleted;
}
public boolean isDirty() {
return dirty;
}
public boolean isDeleted() {
return deleted;
}
public AccountState clone(){
AccountState accountState = new AccountState();
accountState.addToBalance(this.getBalance());
accountState.setNonce(this.getNonce());
accountState.setCodeHash(this.getCodeHash());
accountState.setStateRoot(this.getStateRoot());
return accountState;
}
public String toString() {
String ret = "Nonce: " + this.getNonce().toString() + "\n" +
"Balance: " + Denomination.toFriendlyString(getBalance()) + "\n" +

View File

@ -1,10 +1,7 @@
package org.ethereum.core;
import org.apache.commons.collections4.BidiMap;
import org.apache.commons.collections4.bidimap.DualTreeBidiMap;
import org.codehaus.plexus.util.FileUtils;
import org.ethereum.db.BlockStore;
import org.ethereum.db.ByteArrayWrapper;
import org.ethereum.db.RepositoryImpl;
import org.ethereum.facade.Blockchain;
import org.ethereum.facade.Repository;
import org.ethereum.listener.EthereumListener;
@ -12,7 +9,7 @@ import org.ethereum.manager.WorldManager;
import org.ethereum.net.BlockQueue;
import org.ethereum.net.server.ChannelManager;
import org.ethereum.util.AdvancedDeviceUtils;
import org.ethereum.util.FastByteComparisons;
import org.ethereum.util.ByteUtil;
import org.ethereum.vm.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -20,11 +17,19 @@ import org.spongycastle.util.encoders.Hex;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.math.BigInteger;
import java.util.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import static org.ethereum.config.SystemProperties.CONFIG;
import static org.ethereum.core.Denomination.SZABO;
import static org.ethereum.util.ByteUtil.EMPTY_BYTE_ARRAY;
/**
* The Ethereum blockchain is in many ways similar to the Bitcoin blockchain,
@ -70,6 +75,7 @@ public class BlockchainImpl implements Blockchain {
@Autowired
private Repository repository;
private Repository track;
@Autowired
private BlockStore blockStore;
@ -94,11 +100,6 @@ public class BlockchainImpl implements Blockchain {
private List<Chain> altChains = new ArrayList<>();
private List<Block> garbage = new ArrayList<>();
public BlockchainImpl(){}
public BlockchainImpl(Repository repository) {
this.repository = repository;
}
@Override
public long getGasPrice() {
// In case of the genesis block we don't want to rely on the min gas price
@ -133,12 +134,17 @@ public class BlockchainImpl implements Blockchain {
public void tryToConnect(Block block){
recordBlock(block);
if (logger.isDebugEnabled())
logger.debug("Try connect block: {}",
Hex.toHexString(block.getEncoded()));
if (blockStore.getBlockByHash(block.getHash()) != null){
// retry of well known block
return;
}
// The simple case got the block
// to connect to the main chain
if (bestBlock.isParentOf(block)){
@ -189,13 +195,7 @@ public class BlockchainImpl implements Blockchain {
// if there is too much garbage ask for re-sync
if (garbage.size() > 20){
blockQueue.clear();
totalDifficulty = BigInteger.ZERO;
bestBlock = Genesis.getInstance();
this.repository.close();
this.repository = new RepositoryImpl();
garbage.clear();
altChains.clear();
worldManager.reset();
}
}
@ -203,6 +203,7 @@ public class BlockchainImpl implements Blockchain {
@Override
public void add(Block block) {
track = repository.startTracking();
if (block == null)
return;
@ -215,7 +216,8 @@ public class BlockchainImpl implements Blockchain {
}
this.processBlock(block);
track.commit();
// Remove all wallet transactions as they already approved by the net
worldManager.getWallet().removeTransactions(block.getTransactionsList());
@ -328,10 +330,12 @@ public class BlockchainImpl implements Blockchain {
if(block.getNumber() >= CONFIG.traceStartBlock())
repository.dumpState(block, totalGasUsed, i++, tx.getHash());
}
this.addReward(block);
this.updateTotalDifficulty(block);
this.updateTotalDifficulty(block);
track.commit();
if(block.getNumber() >= CONFIG.traceStartBlock())
repository.dumpState(block, totalGasUsed, 0, null);
}
@ -343,22 +347,19 @@ public class BlockchainImpl implements Blockchain {
* @param block object containing the header and uncles
*/
private void addReward(Block block) {
// Create coinbase if doesn't exist yet
if (repository.getAccountState(block.getCoinbase()) == null)
repository.createAccount(block.getCoinbase());
// Add standard block reward
BigInteger totalBlockReward = Block.BLOCK_REWARD;
// Add extra rewards based on number of uncles
if(block.getUncleList().size() > 0) {
for (BlockHeader uncle : block.getUncleList()) {
repository.addBalance(uncle.getCoinbase(), Block.UNCLE_REWARD);
track.addBalance(uncle.getCoinbase(), Block.UNCLE_REWARD);
}
totalBlockReward = totalBlockReward.add(Block.INCLUSION_REWARD
.multiply(BigInteger.valueOf(block.getUncleList().size())));
}
repository.addBalance(block.getCoinbase(), totalBlockReward);
track.addBalance(block.getCoinbase(), totalBlockReward);
}
@Override
@ -367,18 +368,20 @@ public class BlockchainImpl implements Blockchain {
/* Debug check to see if the state is still as expected */
if(logger.isWarnEnabled()) {
String blockStateRootHash = Hex.toHexString(block.getStateRoot());
String worldStateRootHash = Hex.toHexString(worldManager.getRepository().getWorldState().getRootHash());
String worldStateRootHash = Hex.toHexString(repository.getRoot());
if(!blockStateRootHash.equals(worldStateRootHash)){
stateLogger.warn("BLOCK: STATE CONFLICT! block: {} worldstate {} mismatch", block.getNumber(), worldStateRootHash);
// repository.close();
// System.exit(-1); // Don't add block
// 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
}
}
blockStore.saveBlock(block);
this.setBestBlock(block);
repository.getWorldState().sync();
if (logger.isDebugEnabled())
logger.debug("block added to the blockChain: index: [{}]", block.getNumber());
@ -397,20 +400,17 @@ public class BlockchainImpl implements Blockchain {
*/
public long applyTransaction(Block block, Transaction tx) {
logger.info("applyTransaction: [{}]", Hex.toHexString(tx.getHash()));
byte[] coinbase = block.getCoinbase();
// VALIDATE THE SENDER
byte[] senderAddress = tx.getSender();
AccountState senderAccount = repository.getAccountState(senderAddress);
if (senderAccount == null) {
if (stateLogger.isWarnEnabled())
stateLogger.warn("No such address: {}",
Hex.toHexString(senderAddress));
return 0;
}
// AccountState senderAccount = repository.getAccountState(senderAddress);
logger.info("tx.sender: [{}]", Hex.toHexString(tx.getSender()));
// VALIDATE THE NONCE
BigInteger nonce = senderAccount.getNonce();
BigInteger nonce = track.getNonce(senderAddress);
BigInteger txNonce = new BigInteger(1, tx.getNonce());
if (nonce.compareTo(txNonce) != 0) {
if (stateLogger.isWarnEnabled())
@ -420,7 +420,8 @@ public class BlockchainImpl implements Blockchain {
}
// UPDATE THE NONCE
repository.increaseNonce(senderAddress);
track.increaseNonce(senderAddress);
logger.info("increased tx.nonce to: [{}]", track.getNonce(senderAddress));
// FIND OUT THE TRANSACTION TYPE
byte[] receiverAddress, code = null;
@ -430,31 +431,25 @@ public class BlockchainImpl implements Blockchain {
code = tx.getData(); // init code
} else {
receiverAddress = tx.getReceiveAddress();
if (repository.getAccountState(receiverAddress) == null) {
repository.createAccount(receiverAddress);
if (stateLogger.isDebugEnabled())
stateLogger.debug("new receiver account created address={}",
Hex.toHexString(receiverAddress));
} else {
code = repository.getCode(receiverAddress);
if (code != null) {
if (stateLogger.isDebugEnabled())
stateLogger.debug("calling for existing contract: address={}",
Hex.toHexString(receiverAddress));
}
}
code = track.getCode(receiverAddress);
if (code != EMPTY_BYTE_ARRAY) {
if (stateLogger.isDebugEnabled())
stateLogger.debug("calling for existing contract: address={}",
Hex.toHexString(receiverAddress));
}
}
// THE SIMPLE VALUE/BALANCE CHANGE
boolean isValueTx = tx.getValue() != null;
if (isValueTx) {
BigInteger txValue = new BigInteger(1, tx.getValue());
if (senderAccount.getBalance().compareTo(txValue) >= 0) {
senderAccount.subFromBalance(txValue); // balance will be read again below
repository.addBalance(senderAddress, txValue.negate());
if (track.getBalance(senderAddress).compareTo(txValue) >= 0) {
track.addBalance(receiverAddress, txValue); // balance will be read again below
track.addBalance(senderAddress, txValue.negate());
if(!isContractCreation) // adding to new contract could be reverted
repository.addBalance(receiverAddress, txValue);
// if(!isContractCreation) // adding to new contract could be reverted
// track.addBalance(receiverAddress, txValue); todo: find out what is that ?
if (stateLogger.isDebugEnabled())
stateLogger.debug("Update value balance \n "
@ -469,22 +464,23 @@ public class BlockchainImpl implements Blockchain {
// TODO: performance improve multiply without BigInteger
BigInteger gasPrice = new BigInteger(1, tx.getGasPrice());
BigInteger gasDebit = new BigInteger(1, tx.getGasLimit()).multiply(gasPrice);
logger.info("Gas price limited to [{} wei]", gasDebit.toString());
// Debit the actual total gas value from the sender
// the purchased gas will be available for
// the contract in the execution state,
// it can be retrieved using GAS op
if (gasDebit.signum() == 1) {
if (senderAccount.getBalance().compareTo(gasDebit) == -1) {
if (track.getBalance(senderAddress).compareTo(gasDebit) == -1) {
logger.debug("No gas to start the execution: sender={}",
Hex.toHexString(senderAddress));
return 0;
}
repository.addBalance(senderAddress, gasDebit.negate());
track.addBalance(senderAddress, gasDebit.negate());
// The coinbase get the gas cost
if (coinbase != null)
repository.addBalance(coinbase, gasDebit);
track.addBalance(coinbase, gasDebit);
if (stateLogger.isDebugEnabled())
stateLogger.debug(
@ -495,19 +491,19 @@ public class BlockchainImpl implements Blockchain {
// CREATE AND/OR EXECUTE CONTRACT
long gasUsed = 0;
if (isContractCreation || code != null) {
if (isContractCreation || code != EMPTY_BYTE_ARRAY) {
// START TRACKING FOR REVERT CHANGES OPTION
Repository trackRepository = repository.getTrack();
trackRepository.startTracking();
Repository trackTx = track.startTracking();
logger.info("Start tracking VM run");
try {
// CREATE NEW CONTRACT ADDRESS AND ADD TX VALUE
if(isContractCreation) {
if (isValueTx) // adding to balance also creates the account
trackRepository.addBalance(receiverAddress, new BigInteger(1, tx.getValue()));
trackTx.addBalance(receiverAddress, new BigInteger(1, tx.getValue()));
else
trackRepository.createAccount(receiverAddress);
trackTx.createAccount(receiverAddress);
if(stateLogger.isDebugEnabled())
stateLogger.debug("new contract created address={}",
@ -517,7 +513,7 @@ public class BlockchainImpl implements Blockchain {
Block currBlock = (block == null) ? this.getBestBlock() : block;
ProgramInvoke programInvoke =
programInvokeFactory.createProgramInvoke(tx, currBlock, trackRepository);
programInvokeFactory.createProgramInvoke(tx, currBlock, trackTx);
VM vm = new VM();
Program program = new Program(code, programInvoke);
@ -527,15 +523,15 @@ public class BlockchainImpl implements Blockchain {
program.saveProgramTraceToFile(Hex.toHexString(tx.getHash()));
ProgramResult result = program.getResult();
applyProgramResult(result, gasDebit, gasPrice, trackRepository,
applyProgramResult(result, gasDebit, gasPrice, trackTx,
senderAddress, receiverAddress, coinbase, isContractCreation);
gasUsed = result.getGasUsed();
} catch (RuntimeException e) {
trackRepository.rollback();
trackTx.rollback();
return new BigInteger(1, tx.getGasLimit()).longValue();
}
trackRepository.commit();
trackTx.commit();
} else {
// REFUND GASDEBIT EXCEPT FOR FEE (500 + 5*TXDATA)
long dataCost = tx.getData() == null ? 0: tx.getData().length * GasCost.TXDATA;
@ -543,8 +539,8 @@ public class BlockchainImpl implements Blockchain {
BigInteger refund = gasDebit.subtract(BigInteger.valueOf(gasUsed).multiply(gasPrice));
if (refund.signum() > 0) {
repository.addBalance(senderAddress, refund);
repository.addBalance(coinbase, refund.negate());
track.addBalance(senderAddress, refund);
track.addBalance(coinbase, refund.negate());
}
}
return gasUsed;
@ -665,4 +661,53 @@ public class BlockchainImpl implements Blockchain {
public void setTotalDifficulty(BigInteger totalDifficulty) {
this.totalDifficulty = totalDifficulty;
}
private void recordBlock(Block block){
if (!CONFIG.recordBlocks()) return;
if (bestBlock.isGenesis()){
try {FileUtils.deleteDirectory(CONFIG.dumpDir());} catch (IOException e) {}
}
String dir = CONFIG.dumpDir() + "/";
File dumpFile = new File(System.getProperty("user.dir") + "/" + dir + "_blocks_rec.txt");
FileWriter fw = null;
BufferedWriter bw = null;
try {
dumpFile.getParentFile().mkdirs();
if (!dumpFile.exists()) dumpFile.createNewFile();
fw = new FileWriter(dumpFile.getAbsoluteFile(), true);
bw = new BufferedWriter(fw);
if (bestBlock.isGenesis()){
bw.write(Hex.toHexString(bestBlock.getEncoded()));
bw.write("\n");
}
bw.write(Hex.toHexString(block.getEncoded()));
bw.write("\n");
} catch (IOException e) {
logger.error(e.getMessage(), e);
} finally {
try {
if (bw != null) bw.close();
if (fw != null) fw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}

View File

@ -58,6 +58,8 @@ public class Transaction {
* (including public key recovery bits) */
private ECDSASignature signature;
private byte[] sendAddress;
/* Tx in encoded form */
private byte[] rlpEncoded;
private byte[] rlpRaw;
@ -107,6 +109,9 @@ public class Transaction {
byte[] r = ((RLPItem) transaction.get(7)).getRLPData();
byte[] s = ((RLPItem) transaction.get(8)).getRLPData();
this.signature = ECDSASignature.fromComponents(r, s, v);
} else {
logger.debug("RLP encoded tx is not signed!");
}
@ -182,8 +187,11 @@ public class Transaction {
public byte[] getSender() {
try {
ECKey key = ECKey.signatureToKey(getHash(), getSignature().toBase64());
return key.getAddress();
if (sendAddress == null) {
ECKey key = ECKey.signatureToKey(getHash(), getSignature().toBase64());
sendAddress = key.getAddress();
}
return sendAddress;
} catch (SignatureException e) {
logger.error(e.getMessage(), e);
}

View File

@ -8,10 +8,7 @@ import java.util.Map;
import org.ethereum.trie.Trie;
import org.ethereum.trie.TrieImpl;
import org.ethereum.util.RLP;
import org.ethereum.util.RLPElement;
import org.ethereum.util.RLPItem;
import org.ethereum.util.RLPList;
import org.ethereum.util.*;
import org.ethereum.vm.DataWord;
/**
@ -25,7 +22,10 @@ public class ContractDetails {
private List<DataWord> storageKeys = new ArrayList<>();
private List<DataWord> storageValues = new ArrayList<>();
private byte[] code;
private byte[] code = ByteUtil.EMPTY_BYTE_ARRAY;
private boolean dirty = true;
private boolean deleted = false;
private Trie storageTrie = new TrieImpl(null);
@ -61,6 +61,7 @@ public class ContractDetails {
storageValues.add(value);
}
this.setDirty(true);
this.rlpEncoded = null;
}
@ -82,6 +83,7 @@ public class ContractDetails {
public void setCode(byte[] code) {
this.code = code;
this.setDirty(true);
this.rlpEncoded = null;
}
@ -125,10 +127,27 @@ public class ContractDetails {
storageTrie.update(key.getData(), RLP.encodeElement(value.getNoLeadZeroesData()));
}
this.code = code.getRLPData();
this.code = (code.getRLPData() == null) ? ByteUtil.EMPTY_BYTE_ARRAY : code.getRLPData();
this.rlpEncoded = rlpCode;
}
public void setDirty(boolean dirty) {
this.dirty = dirty;
}
public void setDeleted(boolean deleted) {
this.deleted = deleted;
}
public boolean isDirty() {
return dirty;
}
public boolean isDeleted() {
return deleted;
}
public byte[] getEncoded() {
if (rlpEncoded == null) {
@ -164,5 +183,21 @@ public class ContractDetails {
return Collections.unmodifiableMap(storage);
}
public void setStorage(List<DataWord> storageKeys, List<DataWord> storageValues) {
this.storageKeys = storageKeys;
this.storageValues = storageValues;
}
public ContractDetails clone(){
ContractDetails contractDetails = new ContractDetails();
contractDetails.setCode(this.getCode());
contractDetails.setStorage(new ArrayList<DataWord>(this.storageKeys) ,
new ArrayList<DataWord>(this.storageValues));
return contractDetails;
}
}

View File

@ -89,11 +89,19 @@ public class DatabaseImpl implements Database {
@Override
public void put(byte[] key, byte[] value) {
if(logger.isDebugEnabled())
logger.debug("put: key: [{}], value: [{}]",
Hex.toHexString(key),
Hex.toHexString(value));
db.put(key, value);
}
@Override
public void delete(byte[] key) {
if(logger.isDebugEnabled())
logger.debug("delete: key: [{}]");
db.delete(key);
}

View File

@ -5,16 +5,14 @@ import com.fasterxml.jackson.databind.node.ObjectNode;
import org.codehaus.plexus.util.FileUtils;
import org.ethereum.core.AccountState;
import org.ethereum.core.Block;
import org.ethereum.crypto.HashUtil;
import org.ethereum.facade.Repository;
import org.ethereum.json.EtherObjectMapper;
import org.ethereum.json.JSONHelper;
import org.ethereum.trie.TrackTrie;
import org.ethereum.trie.Trie;
import org.ethereum.trie.TrieImpl;
import org.ethereum.util.ByteUtil;
import org.ethereum.vm.DataWord;
import org.iq80.leveldb.DBIterator;
import org.iq80.leveldb.WriteBatch;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.spongycastle.util.encoders.Hex;
@ -25,90 +23,60 @@ import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.math.BigInteger;
import java.util.HashMap;
import java.util.List;
import static org.ethereum.config.SystemProperties.CONFIG;
import static org.ethereum.crypto.SHA3Helper.*;
/**
*
***********************************************************************************
Repository<br>
|<br>
--&gt; AccountState ---&gt; Trie ---&gt; leveldb (state) /key=address<br>
--&gt; nonce<br>
--&gt; balance<br>
--&gt; stateRoot<br>
--&gt; codeHash<br>
|<br>
--&gt; ContractDetails ---&gt; leveldb(details) /key=address<br>
--&gt; code ---&gt; sha3(code) // saved into AccountInfo.codeHash<br>
--&gt; storage ---&gt; Trie // to calculate the AccountInfo.stateRoot<br>
***********************************************************************************
*
* www.ethereumJ.com
* www.etherj.com
*
* @author: Roman Mandeleil
* Created on: 23/06/2014 23:01
* Created on: 17/11/2014 21:15
*/
@Component
public class RepositoryImpl implements Repository {
final static String DETAILS_DB = "details";
final static String STATE_DB = "state";
private static final Logger logger = LoggerFactory.getLogger("repository");
private Trie worldState;
private TrackTrie accountStateDB;
private TrackDatabase contractDetailsDB;
// TODO: Listeners listeners
// TODO: cash impl
private DatabaseImpl detailsDB = null;
private DatabaseImpl stateDB = null;
/**
* Create a new Repository DAO
* assuming empty db and thus no stateRoot
*
*/
public RepositoryImpl() {
this("details", "state");
this(DETAILS_DB, STATE_DB);
}
public RepositoryImpl(String detailsDbName, String stateDbName) {
detailsDB = new DatabaseImpl(detailsDbName);
contractDetailsDB = new TrackDatabase(detailsDB);
stateDB = new DatabaseImpl(stateDbName);
worldState = new TrieImpl(stateDB.getDb());
accountStateDB = new TrackTrie(worldState);
detailsDB = new DatabaseImpl(detailsDbName);
stateDB = new DatabaseImpl(stateDbName);
worldState = new TrieImpl(stateDB.getDb());
}
private RepositoryImpl(TrackTrie accountStateDB, TrackDatabase contractDetailsDB) {
this.accountStateDB = accountStateDB;
this.contractDetailsDB = contractDetailsDB;
@Override
public void reset() {
close();
detailsDB = new DatabaseImpl(DETAILS_DB);
stateDB = new DatabaseImpl(STATE_DB);
worldState = new TrieImpl(stateDB.getDb());
}
public Repository getTrack() {
TrackTrie trackState = new TrackTrie(accountStateDB);
TrackDatabase trackDetails = new TrackDatabase(contractDetailsDB);
return new RepositoryImpl(trackState, trackDetails);
}
public void startTracking() {
logger.debug("start tracking");
accountStateDB.startTrack();
contractDetailsDB.startTrack();
}
public void commit() {
logger.debug("commit changes");
accountStateDB.commitTrack();
contractDetailsDB.commitTrack();
}
public void rollback() {
logger.debug("rollback changes");
accountStateDB.rollbackTrack();
contractDetailsDB.rollbackTrack();
@Override
public void close() {
if (this.detailsDB != null){
detailsDB.close();
detailsDB = null;
}
if (this.stateDB != null){
stateDB.close();
stateDB = null;
}
}
@Override
@ -116,210 +84,95 @@ public class RepositoryImpl implements Repository {
return stateDB == null;
}
public AccountState createAccount(byte[] addr) {
@Override
public void updateBatch(HashMap<ByteArrayWrapper, AccountState> stateCache,
HashMap<ByteArrayWrapper, ContractDetails> detailsCache) {
logger.trace("createAccount: [{}]", Hex.toHexString(addr)) ;
this.validateAddress(addr);
// 1. Save AccountState
AccountState state = new AccountState();
accountStateDB.update(addr, state.getEncoded());
ContractDetails details = new ContractDetails();
contractDetailsDB.put(addr, details.getEncoded());
if (logger.isDebugEnabled())
logger.debug("New account created: [{}]", Hex.toHexString(addr));
WriteBatch writeBatch = detailsDB.getDb().createWriteBatch();
for (ByteArrayWrapper hash : detailsCache.keySet()) {
return state;
}
public Trie getWorldState() {
return worldState;
ContractDetails contractDetails = detailsCache.get(hash);
if (contractDetails.isDeleted())
writeBatch.delete(hash.getData());
else{
if (contractDetails.isDirty())
writeBatch.put(hash.getData(), contractDetails.getEncoded());
}
if (contractDetails.isDirty() || contractDetails.isDeleted()){
AccountState accountState = stateCache.get(hash);
accountState.setStateRoot(contractDetails.getStorageHash());
accountState.setCodeHash(sha3(contractDetails.getCode()));
}
contractDetails.setDeleted(false);
contractDetails.setDirty(false);
}
detailsDB.getDb().write(writeBatch);
for (ByteArrayWrapper hash : detailsCache.keySet()) {
AccountState accountState = stateCache.get(hash);
if (accountState.isDeleted())
worldState.delete(hash.getData());
else{
if (accountState.isDirty())
worldState.update(hash.getData(), accountState.getEncoded());
}
accountState.setDeleted(false);
accountState.setDirty(false);
}
worldState.sync();
}
public AccountState getAccountState(byte[] addr) {
if (logger.isDebugEnabled())
logger.debug("Get account state for: [{}]", Hex.toHexString(addr));
this.validateAddress(addr);
byte[] accountStateRLP = accountStateDB.get(addr);
if (logger.isDebugEnabled())
logger.debug("Found account state RLP: [{}]", Hex.toHexString(accountStateRLP));
if (accountStateRLP == null || accountStateRLP.length == 0)
return null;
AccountState state = new AccountState(accountStateRLP);
return state;
@Override
public void rollback() {
throw new UnsupportedOperationException();
}
public ContractDetails getContractDetails(byte[] addr) {
this.validateAddress(addr);
if (logger.isDebugEnabled())
logger.debug("Get contract details for: [{}]", Hex.toHexString(addr));
byte[] accountDetailsRLP = contractDetailsDB.get(addr);
if (accountDetailsRLP == null)
return null;
if (logger.isDebugEnabled())
logger.debug("Found contract details RLP: [{}]", Hex.toHexString(accountDetailsRLP));
ContractDetails details = new ContractDetails(accountDetailsRLP);
return details;
}
public BigInteger addBalance(byte[] addr, BigInteger value) {
AccountState state = getAccountState(addr);
if (state == null)
state = createAccount(addr);
BigInteger newBalance = state.addToBalance(value);
if (logger.isDebugEnabled())
logger.debug("Changing balance: \n account:\t [{}]\n new balance:\t [{}]\n delta:\t\t [{}]",
Hex.toHexString(addr), newBalance.toString(), value);
accountStateDB.update(addr, state.getEncoded());
return newBalance;
}
public BigInteger getBalance(byte[] addr) {
AccountState state = getAccountState(addr);
if (state == null) return BigInteger.ZERO;
return state.getBalance();
@Override
public void commit() {
throw new UnsupportedOperationException();
}
public BigInteger getNonce(byte[] addr) {
AccountState state = getAccountState(addr);
if (state == null) return BigInteger.ZERO;
return state.getNonce();
@Override
public void syncToRoot(byte[] root) {
worldState.setRoot(root);
}
public BigInteger increaseNonce(byte[] addr) {
AccountState state = getAccountState(addr);
if (state == null) return BigInteger.ZERO;
state.incrementNonce();
if (logger.isDebugEnabled())
logger.debug("Increment nonce:\n account:\t [{}]\n new nonce:\t [{}]",
Hex.toHexString(addr), state.getNonce().longValue());
accountStateDB.update(addr, state.getEncoded());
return state.getNonce();
}
public void addStorageRow(byte[] addr, DataWord key, DataWord value) {
if (key == null) return;
AccountState state = getAccountState(addr);
ContractDetails details = getContractDetails(addr);
if (state == null || details == null) return;
details.put(key, value);
byte[] storageHash = details.getStorageHash();
state.setStateRoot(storageHash);
if (logger.isDebugEnabled())
logger.debug("Storage key/value saved:\n account:\t [{}]\n key:\t\t [{}]\n value:\t\t [{}]\n new hash:\t [{}]",
Hex.toHexString(addr),
Hex.toHexString(key.getNoLeadZeroesData()),
Hex.toHexString(value.getNoLeadZeroesData()),
Hex.toHexString(storageHash));
accountStateDB.update(addr, state.getEncoded());
contractDetailsDB.put(addr, details.getEncoded());
}
public DataWord getStorageValue(byte[] addr, DataWord key) {
if (key == null) return null;
AccountState state = getAccountState(addr);
if (state == null) return null;
ContractDetails details = getContractDetails(addr);
DataWord value = details.get(key);
return value;
}
public byte[] getCode(byte[] addr) {
ContractDetails details = getContractDetails(addr);
if (details == null) return null;
return details.getCode();
}
public void saveCode(byte[] addr, byte[] code) {
if (code == null) return;
AccountState state = getAccountState(addr);
if (state == null) return;
if (logger.isDebugEnabled())
logger.debug("Saving code: \n address:\t [{}], \n code:\t\t [{}]",
Hex.toHexString(addr),
Hex.toHexString(code));
ContractDetails details = getContractDetails(addr);
details.setCode(code);
byte[] codeHash = HashUtil.sha3(code);
state.setCodeHash(codeHash);
accountStateDB.update(addr, state.getEncoded());
contractDetailsDB.put(addr, details.getEncoded());
if (logger.isDebugEnabled())
logger.debug("Code saved: \n accountstate:\t [{}]\n codeHash:\t [{}]\n details RLP:\t [{}]",
Hex.toHexString(state.getEncoded()),
Hex.toHexString(codeHash),
Hex.toHexString(details.getEncoded()));
}
public void delete(byte[] addr) {
this.validateAddress(addr);
accountStateDB.delete(addr);
contractDetailsDB.delete(addr);
}
public List<ByteArrayWrapper> dumpKeys() {
return stateDB.dumpKeys();
@Override
public Repository startTracking() {
return new RepositoryTrack(this);
}
@Override
public void dumpState(Block block, long gasUsed, int txNumber, byte[] txHash) {
dumpTrie(block);
if (!(CONFIG.dumpFull() || CONFIG.dumpBlock() == block.getNumber()))
return;
if (!(CONFIG.dumpFull() || CONFIG.dumpBlock() == block.getNumber()))
return;
// todo: dump block header and the relevant tx
if (block.getNumber() == 0 && txNumber == 0)
if (CONFIG.dumpCleanOnRestart()) {
try {FileUtils.deleteDirectory(CONFIG.dumpDir());} catch (IOException e) {}
try {
FileUtils.deleteDirectory(CONFIG.dumpDir());} catch (IOException e) {}
}
String dir = CONFIG.dumpDir() + "/";
String fileName = "";
if (txHash != null)
fileName = String.format("%07d_%d_%s.dmp", block.getNumber(), txNumber,
Hex.toHexString(txHash).substring(0, 8));
else {
fileName = String.format("%07d_c.dmp", block.getNumber());
}
fileName = String.format("%07d_%d_%s.dmp", block.getNumber(), txNumber,
Hex.toHexString(txHash).substring(0, 8));
else {
fileName = String.format("%07d_c.dmp", block.getNumber());
}
File dumpFile = new File(System.getProperty("user.dir") + "/" + dir + fileName);
FileWriter fw = null;
@ -333,29 +186,29 @@ public class RepositoryImpl implements Repository {
bw = new BufferedWriter(fw);
List<ByteArrayWrapper> keys = this.detailsDB.dumpKeys();
JsonNodeFactory jsonFactory = new JsonNodeFactory(false);
ObjectNode blockNode = jsonFactory.objectNode();
JSONHelper.dumpBlock(blockNode, block, gasUsed,
this.getWorldState().getRootHash(),
this.getRoot(),
keys, this);
EtherObjectMapper mapper = new EtherObjectMapper();
bw.write(mapper.writeValueAsString(blockNode));
} catch (IOException e) {
logger.error(e.getMessage(), e);
logger.error(e.getMessage(), e);
} finally {
try {
if (bw != null) bw.close();
if (fw != null) fw.close();
} catch (IOException e) {
e.printStackTrace();
}
if (bw != null) bw.close();
if (fw != null) fw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public void dumpTrie(Block block){
if (!(CONFIG.dumpFull() || CONFIG.dumpBlock() == block.getNumber()))
@ -367,7 +220,7 @@ public class RepositoryImpl implements Repository {
FileWriter fw = null;
BufferedWriter bw = null;
String dump = this.getWorldState().getTrieDump();
String dump = this.worldState.getTrieDump();
try {
@ -389,35 +242,156 @@ public class RepositoryImpl implements Repository {
}
}
@Override
public DBIterator getAccountsIterator() {
return detailsDB.iterator();
return detailsDB.iterator();
}
public void close() {
if (this.detailsDB != null){
detailsDB.close();
detailsDB = null;
@Override
public BigInteger addBalance(byte[] addr, BigInteger value) {
AccountState account = getAccountState(addr);
if (account == null)
account = createAccount(addr);
BigInteger result = account.addToBalance(value);
worldState.update(addr, account.getEncoded());
return result;
}
@Override
public BigInteger getBalance(byte[] addr) {
AccountState account = getAccountState(addr);
if (account == null)
return BigInteger.ZERO;
return account.getBalance();
}
@Override
public DataWord getStorageValue(byte[] addr, DataWord key) {
ContractDetails details = getContractDetails(addr);
if (details == null)
return null;
return details.get(key);
}
@Override
public void addStorageRow(byte[] addr, DataWord key, DataWord value) {
ContractDetails details = getContractDetails(addr);
if (details == null){
createAccount(addr);
details = getContractDetails(addr);
}
if (this.stateDB != null){
stateDB.close();
stateDB = null;
details.put(key, value);
detailsDB.put(addr, details.getEncoded());
}
@Override
public byte[] getCode(byte[] addr) {
ContractDetails details = getContractDetails(addr);
if (details == null)
return null;
return details.getCode();
}
@Override
public void saveCode(byte[] addr, byte[] code) {
ContractDetails details = getContractDetails(addr);
if (details == null){
createAccount(addr);
details = getContractDetails(addr);
}
details.setCode(code);
detailsDB.put(addr, details.getEncoded());
}
private void validateAddress(byte[] addr) {
if (addr == null || addr.length < 20) {
logger.error("Can't create address {} because is null or length != 20", ByteUtil.toHexString(addr));
throw new IllegalArgumentException("Address must be a byte-array of length 20");
}
@Override
public BigInteger getNonce(byte[] addr) {
AccountState account = getAccountState(addr);
if (account == null)
account = createAccount(addr);
return account.getNonce();
}
public void reset(){
close();
detailsDB = new DatabaseImpl("details");
contractDetailsDB = new TrackDatabase(detailsDB);
stateDB = new DatabaseImpl("state");
worldState = new TrieImpl(stateDB.getDb());
accountStateDB = new TrackTrie(worldState);
@Override
public BigInteger increaseNonce(byte[] addr) {
AccountState account = getAccountState(addr);
if (account == null)
account = createAccount(addr);
account.incrementNonce();
worldState.update(addr, account.getEncoded());
return account.getNonce();
}
@Override
public void delete(byte[] addr) {
worldState.delete(addr);
detailsDB.delete(addr);
}
@Override
public ContractDetails getContractDetails(byte[] addr) {
ContractDetails result = null;
byte[] detailsData = detailsDB.get(addr);
if (detailsData != null)
result = new ContractDetails(detailsData);
return result;
}
@Override
public AccountState getAccountState(byte[] addr) {
AccountState result = null;
byte[] accountData = worldState.get(addr);
if (accountData.length != 0)
result = new AccountState(accountData);
return result;
}
@Override
public AccountState createAccount(byte[] addr) {
AccountState accountState = new AccountState();
worldState.update(addr, accountState.getEncoded());
ContractDetails contractDetails = new ContractDetails();
detailsDB.put(addr, contractDetails.getEncoded());
return accountState;
}
@Override
public byte[] getRoot() {
return worldState.getRootHash();
}
}

View File

@ -0,0 +1,235 @@
package org.ethereum.db;
import org.ethereum.core.AccountState;
import org.ethereum.core.Block;
import org.ethereum.facade.Repository;
import org.ethereum.vm.DataWord;
import org.iq80.leveldb.DBIterator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.spongycastle.util.encoders.Hex;
import java.math.BigInteger;
import java.util.HashMap;
import static org.ethereum.crypto.SHA3Helper.sha3;
import static org.ethereum.util.ByteUtil.wrap;
/**
* www.etherj.com
*
* @author: Roman Mandeleil
* Created on: 17/11/2014 21:15
*/
public class RepositoryTrack implements Repository {
private static final Logger logger = LoggerFactory.getLogger("repository");
HashMap<ByteArrayWrapper, AccountState> cacheAccounts = new HashMap<>();
HashMap<ByteArrayWrapper, ContractDetails> cacheDetails = new HashMap<>();
Repository repository;
public RepositoryTrack(Repository repository) {
this.repository = repository;
}
@Override
public AccountState createAccount(byte[] addr) {
logger.trace("createAccount: [{}]", Hex.toHexString(addr)) ;
AccountState accountState = new AccountState();
cacheAccounts.put(wrap(addr), accountState);
ContractDetails contractDetails = new ContractDetails();
cacheDetails.put(wrap(addr), contractDetails);
return accountState;
}
@Override
public AccountState getAccountState(byte[] addr) {
AccountState accountState = cacheAccounts.get(wrap(addr));
if (accountState == null){
accountState = repository.getAccountState(addr);
if (accountState == null){
accountState = createAccount(addr);
} else {
accountState = accountState.clone();
cacheAccounts.put(wrap(addr), accountState);
ContractDetails contractDetails = repository.getContractDetails(addr);
cacheDetails.put(wrap(addr), contractDetails.clone());
}
}
return accountState;
}
@Override
public ContractDetails getContractDetails(byte[] addr) {
getAccountState(addr);
ContractDetails contractDetails = cacheDetails.get(wrap(addr));
return contractDetails;
}
@Override
public void delete(byte[] addr) {
logger.trace("delete account: [{}]", Hex.toHexString(addr)) ;
getAccountState(addr).setDeleted(true);
getContractDetails(addr).setDeleted(true);
}
@Override
public BigInteger increaseNonce(byte[] addr) {
AccountState accountState = getAccountState(addr);
if (accountState == null)
accountState = createAccount(addr);
BigInteger saveNonce = accountState.getNonce();
accountState.incrementNonce();
logger.trace("increase nonce addr: [{}], from: [{}], to: [{}]", Hex.toHexString(addr),
saveNonce, accountState.getNonce());
return accountState.getNonce();
}
@Override
public BigInteger getNonce(byte[] addr) {
AccountState accountState = getAccountState(addr);
return accountState == null ? BigInteger.ZERO : accountState.getNonce();
}
@Override
public BigInteger getBalance(byte[] addr) {
AccountState accountState = getAccountState(addr);
return accountState == null ? BigInteger.ZERO : accountState.getBalance();
}
@Override
public BigInteger addBalance(byte[] addr, BigInteger value) {
AccountState accountState = getAccountState(addr);
if (accountState == null){
accountState = createAccount(addr);
}
logger.trace("adding to balance addr: [{}], balance: [{}], delta: [{}]", Hex.toHexString(addr),
accountState.getBalance(), value);
return accountState.addToBalance(value);
}
@Override
public void saveCode(byte[] addr, byte[] code) {
logger.trace("saving code addr: [{}], code: [{}]", Hex.toHexString(addr),
Hex.toHexString(code));
getContractDetails(addr).setCode(code);
getAccountState(addr).setCodeHash(sha3(code));
}
@Override
public byte[] getCode(byte[] addr) {
return getContractDetails(addr).getCode();
}
@Override
public void addStorageRow(byte[] addr, DataWord key, DataWord value) {
logger.trace("add storage row, addr: [{}], key: [{}] val: [{}]", Hex.toHexString(addr),
key.toString(), value.toString());
getContractDetails(addr).put(key, value);
}
@Override
public DataWord getStorageValue(byte[] addr, DataWord key) {
return getContractDetails(addr).get(key);
}
@Override
public DBIterator getAccountsIterator() {
throw new UnsupportedOperationException();
}
@Override
public void dumpState(Block block, long gasUsed, int txNumber, byte[] txHash) {
throw new UnsupportedOperationException();
}
@Override
public Repository startTracking() {
logger.debug("start tracking");
return new RepositoryTrack(this);
}
@Override
public void commit() {
logger.debug("commit changes");
repository.updateBatch(cacheAccounts, cacheDetails);
}
@Override
public void syncToRoot(byte[] root) {
throw new UnsupportedOperationException();
}
@Override
public void rollback() {
logger.debug("rollback changes");
cacheAccounts.clear();
cacheDetails.clear();
}
@Override
public void updateBatch(HashMap<ByteArrayWrapper, AccountState> accountStates,
HashMap<ByteArrayWrapper, ContractDetails> contractDetailes){
for (ByteArrayWrapper hash : accountStates.keySet()){
cacheAccounts.put(hash, accountStates.get(hash));
}
for (ByteArrayWrapper hash : contractDetailes.keySet()){
cacheDetails.put(hash, contractDetailes.get(hash));
}
}
@Override // that's the idea track is here not for root calculations
public byte[] getRoot() {
throw new UnsupportedOperationException();
}
@Override
public boolean isClosed() {
throw new UnsupportedOperationException();
}
@Override
public void close() {
throw new UnsupportedOperationException();
}
@Override
public void reset() {
throw new UnsupportedOperationException();
}
}

View File

@ -73,7 +73,6 @@ public class EthereumFactory {
System.setProperty("hsqldb.reconfig_logging", "false");
String url =
String.format("jdbc:hsqldb:file:./%s/blockchain/blockchain.db;" +
"create=%s;hsqldb.default_table_type=cached",
@ -86,6 +85,7 @@ public class EthereumFactory {
ds.setUrl(url);
ds.setUsername("sa");
return ds;
}

View File

@ -1,20 +1,17 @@
package org.ethereum.facade;
import java.math.BigInteger;
import org.ethereum.core.AccountState;
import org.ethereum.core.Block;
import org.ethereum.db.ByteArrayWrapper;
import org.ethereum.db.ContractDetails;
import org.ethereum.db.DatabaseImpl;
import org.ethereum.db.TrackDatabase;
import org.ethereum.trie.TrackTrie;
import org.ethereum.trie.Trie;
import org.ethereum.trie.TrieImpl;
import org.ethereum.vm.DataWord;
import org.iq80.leveldb.DBIterator;
import java.math.BigInteger;
import java.util.HashMap;
/**
* www.ethereumJ.com
* www.etherj.com
*
* @author: Roman Mandeleil
* Created on: 08/09/2014 10:25
@ -93,7 +90,8 @@ public interface Repository {
* @param value is the data to store
*/
public void addStorageRow(byte[] addr, DataWord key, DataWord value);
/**
* Retrieve storage value from an account for a given key
*
@ -127,14 +125,7 @@ public interface Repository {
* @return an iterator over the accounts in this database in proper sequence
*/
public DBIterator getAccountsIterator();
/**
* Return the current state as the Trie data structure
*
* @return the <code>Trie</code> representing the entire current state
*/
public Trie getWorldState();
/**
* Dump the full state of the current repository into a file with JSON format
@ -146,19 +137,14 @@ public interface Repository {
* @param txHash is the hash of the given transaction.
* If null, the block state post coinbase reward is dumped.
*/
public void dumpState(Block block, long gasUsed, int txNumber, byte[] txHash);
public void dumpState(Block block, long gasUsed, int txNumber, byte[] txHash);
/**
* Start tracking the database changes
* Save a snapshot and start tracking future changes
*
* @return the tracker repository
*/
public void startTracking();
/**
* Return a repository snapshot of the current state
*
* @return the repository in its current state
*/
public Repository getTrack();
public Repository startTracking();
/**
* Store all the temporary changes made
@ -171,6 +157,13 @@ public interface Repository {
* to a snapshot of the repository
*/
public void rollback();
/**
* Return to one of the previous snapshots
* by moving the root.
* @param root - new root
*/
public void syncToRoot(byte[] root);
/**
* Check to see if the current repository has an open connection to the database
@ -188,4 +181,10 @@ public interface Repository {
*/
public void reset();
public void updateBatch(HashMap<ByteArrayWrapper, AccountState> accountStates,
HashMap<ByteArrayWrapper, ContractDetails> contractDetailes);
public byte[] getRoot();
}

View File

@ -157,11 +157,15 @@ public class WorldManager {
repository.createAccount(Hex.decode(address));
repository.addBalance(Hex.decode(address), Genesis.PREMINE_AMOUNT);
}
blockchain.storeBlock(Genesis.getInstance());
blockStore.saveBlock(Genesis.getInstance());
blockchain.setBestBlock(Genesis.getInstance());
blockchain.setTotalDifficulty(BigInteger.ZERO);
repository.dumpState(Genesis.getInstance(), 0, 0, null);
logger.info("Genesis block loaded");
} else {
blockchain.setBestBlock(bestBlock);
@ -181,16 +185,25 @@ public class WorldManager {
// update world state by dummy hash
byte[] rootHash = Hex.decode(CONFIG.rootHashStart());
logger.info("Loading root hash from property file: [{}]", CONFIG.rootHashStart());
this.repository.getWorldState().setRoot(rootHash);
this.repository.syncToRoot(rootHash);
} else{
// Update world state to latest loaded block from db
this.repository.getWorldState().setRoot(blockchain.getBestBlock().getStateRoot());
this.repository.syncToRoot(blockchain.getBestBlock().getStateRoot());
}
/* todo: return it when there is no state conflicts on the chain
boolean dbValid = this.repository.getWorldState().validate() || bestBlock.isGenesis();
if (!dbValid){
logger.error("The DB is not valid for that blockchain");
System.exit(-1); // todo: reset the repository and blockchain
}
*/
}
public void reset(){
logger.info("Resetting blockchain ");
repository.reset();
blockchain.reset();
loadBlockchain();

View File

@ -65,7 +65,7 @@ public class BlockQueue {
Block block = blockReceivedQueue.poll();
logger.info("Processing block index: {}", block.getNumber());
blockchain.add(block);
blockchain.tryToConnect(block);
}
}

View File

@ -425,7 +425,7 @@ public class EthHandler extends SimpleChannelInboundHandler<EthMessage> {
}
sendGetBlocks();
}
}, 1000, 300);
}, 300, 10);
}
private void stopGetBlocksTimer() {

View File

@ -7,6 +7,7 @@ import org.ethereum.crypto.HashUtil;
import org.ethereum.db.ByteArrayWrapper;
import org.ethereum.util.Value;
import org.iq80.leveldb.DB;
import org.iq80.leveldb.WriteBatch;
/**
* www.ethereumJ.com
@ -74,17 +75,18 @@ public class Cache {
return;
}
WriteBatch batch = db.createWriteBatch();
for (ByteArrayWrapper key : this.nodes.keySet()) {
Node node = this.nodes.get(key);
if (node.isDirty()) {
this.db.put(key.getData(), node.getValue().encode());
batch.put(key.getData(), node.getValue().encode());
node.setDirty(false);
}
}
db.write(batch);
this.isDirty = false;
// TODO come up with a way to clean up this.nodes
// from memory without breaking consensus
}
public void undo() {

View File

@ -1,108 +0,0 @@
package org.ethereum.trie;
import org.ethereum.db.ByteArrayWrapper;
import org.ethereum.util.ByteUtil;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* The TrackTrie is a wrapper around and actual Modified Merkle Patricia Trie
* to keep track of changes which can be rolled back or committed down into
* the original trie after successful execution of a transaction.
*
* www.ethereumJ.com
* @author: Roman Mandeleil
* Created on: 11/06/2014 19:47
*/
public class TrackTrie implements Trie {
private Trie trie;
private boolean trackingChanges = false;
private Map<ByteArrayWrapper, byte[]> changes;
private List<ByteArrayWrapper> deletes;
public TrackTrie(Trie trie) {
this.trie = trie;
}
public void startTrack() {
changes = new HashMap<>();
deletes = new ArrayList<>();
trackingChanges = true;
}
public void commitTrack() {
for (ByteArrayWrapper key : changes.keySet())
trie.update(key.getData(), changes.get(key));
for (ByteArrayWrapper key : deletes)
trie.update(key.getData(), ByteUtil.EMPTY_BYTE_ARRAY);
changes = null;
trackingChanges = false;
}
public void rollbackTrack() {
changes = new HashMap<>();
deletes = new ArrayList<>();
changes = null;
trackingChanges = false;
}
@Override
public void update(byte[] key, byte[] value) {
if (trackingChanges)
changes.put(new ByteArrayWrapper(key), value);
else
trie.update(key, value);
}
@Override
public byte[] get(byte[] key) {
if (trackingChanges) {
ByteArrayWrapper wKey = new ByteArrayWrapper(key);
if (deletes.contains(wKey))
return null;
if (changes.get(wKey) != null)
return changes.get(wKey);
return trie.get(key);
}
return trie.get(key);
}
@Override
public void delete(byte[] key) {
if (trackingChanges) {
ByteArrayWrapper wKey = new ByteArrayWrapper(key);
deletes.add(wKey);
} else
trie.delete(key);
}
@Override
public byte[] getRootHash() {
return trie.getRootHash();
}
@Override
public String getTrieDump() {
return trie.getTrieDump();
}
@Override
public void setRoot(byte[] root) {
trie.setRoot(root);
}
@Override
public void sync() {
trie.sync();
}
@Override
public void undo() {
trie.undo();
}
}

View File

@ -54,4 +54,7 @@ public interface Trie {
public void undo();
public String getTrieDump();
public boolean validate();
}

View File

@ -510,4 +510,12 @@ public class TrieImpl implements Trie {
public interface ScanAction {
public void doOnNode(byte[] hash, Value node);
}
public boolean validate(){
if (cache.get(getRootHash()) != null)
return true;
else
return false;
}
}

View File

@ -6,6 +6,7 @@ import java.math.BigInteger;
import java.nio.ByteBuffer;
import java.util.Arrays;
import org.ethereum.db.ByteArrayWrapper;
import org.spongycastle.util.encoders.Hex;
public class ByteUtil {
@ -287,4 +288,9 @@ public class ByteUtil {
System.arraycopy(src, 0, dest, dest.length - src.length, src.length);
return dest;
}
public static ByteArrayWrapper wrap(byte[] data){
return new ByteArrayWrapper(data);
}
}

View File

@ -297,17 +297,16 @@ public class Program {
result.getRepository().addBalance(senderAddress, endowment.negate());
BigInteger newBalance = result.getRepository().addBalance(newAddress, endowment);
Repository trackRepository = result.getRepository().getTrack();
trackRepository.startTracking();
Repository track = result.getRepository().startTracking();
// [3] UPDATE THE NONCE
// (THIS STAGE IS NOT REVERTED BY ANY EXCEPTION)
trackRepository.increaseNonce(senderAddress);
track.increaseNonce(senderAddress);
// [5] COOK THE INVOKE AND EXECUTE
ProgramInvoke programInvoke = ProgramInvokeFactory.createProgramInvoke(
this, new DataWord(newAddress), DataWord.ZERO, gasLimit,
newBalance, null, trackRepository);
newBalance, null, track);
ProgramResult result = null;
@ -324,15 +323,15 @@ public class Program {
result.getException() instanceof Program.OutOfGasException) {
logger.info("contract run halted by OutOfGas: new contract init ={}" , Hex.toHexString(newAddress));
trackRepository.rollback();
track.rollback();
stackPushZero();
return;
}
// 4. CREATE THE CONTRACT OUT OF RETURN
byte[] code = result.getHReturn().array();
trackRepository.saveCode(newAddress, code);
trackRepository.commit();
track.saveCode(newAddress, code);
track.commit();
// IN SUCCESS PUSH THE ADDRESS INTO THE STACK
stackPush(new DataWord(newAddress));
@ -402,9 +401,7 @@ public class Program {
// actual gas subtract
this.spendGas(msg.getGas().longValue(), "internal call");
Repository trackRepository = result.getRepository().getTrack();
trackRepository.startTracking();
Repository trackRepository = result.getRepository().startTracking();
ProgramInvoke programInvoke = ProgramInvokeFactory.createProgramInvoke(
this, new DataWord(contextAddress), msg.getEndowment(),
msg.getGas(), contextBalance, data, trackRepository);

View File

@ -6,7 +6,7 @@ log4j.logger.dump=TRACE, DUMP
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{HH:mm:ss} [%c{1}] %m%n
log4j.appender.stdout.layout.ConversionPattern=%d{HH:mm:ss.SSS} [%c{1}] %m%n
log4j.appender.stdout.Threshold=TRACE
# Direct log messages to stdout
@ -31,19 +31,18 @@ log4j.logger.peerdiscovery = TRACE
log4j.logger.peermonitor = TRACE
log4j.logger.java.nio = ERROR
log4j.logger.io.netty = ERROR
log4j.logger.wire = TRACE
log4j.logger.wire = ERROR
log4j.logger.VM = ERROR
log4j.logger.main = ERROR
log4j.logger.trie = ERROR
log4j.logger.state = INFO
log4j.logger.repository = INFO
log4j.logger.blockchain = TRACE
log4j.logger.repository = TRACE
log4j.logger.blockchain = DEBUG
log4j.logger.txs = ERROR
log4j.logger.ui = ERROR
log4j.logger.gas = ERROR
log4j.logger.cli = INFO
log4j.logger.org.springframework = ERROR
log4j.logger.org.hibernate = ERROR
log4j.logger.hsqldb.db = ERROR

View File

@ -1,7 +1,3 @@
# if the system will work as a server also
# accept for incoming connections [true/false]
server.acceptConnections = false
# List of the peers to start
# the search of the online peers
# values: [ip:port, ip:port, ip:port ...]

View File

@ -70,19 +70,19 @@ public class TestContext {
System.setProperty("hsqldb.reconfig_logging", "false");
String url =
String.format("jdbc:hsqldb:file:./%s/blockchain/blockchain.db;" +
"create=%s;hsqldb.default_table_type=cached",
String.format("jdbc:hsqldb:file:./%s/blockchain/blockchain.db;" +
"create=%s;hsqldb.default_table_type=cached",
SystemProperties.CONFIG.databaseDir(),
SystemProperties.CONFIG.databaseReset());
SystemProperties.CONFIG.databaseDir(),
SystemProperties.CONFIG.databaseReset());
DriverManagerDataSource ds = new DriverManagerDataSource();
ds.setDriverClassName("org.hsqldb.jdbcDriver");
ds.setUrl(url);
ds.setUsername("sa");
return ds;
}

View File

@ -21,8 +21,16 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.support.AnnotationConfigContextLoader;
import test.ethereum.TestContext;
import java.io.File;
import java.io.IOException;
import java.math.BigInteger;
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.junit.Assert.*;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
@ -183,6 +191,84 @@ public class BlockTest {
assertEquals(actualGasLimit, calcGasLimit);
}
@Test
public void testScenario1() throws URISyntaxException, IOException {
BlockchainImpl blockchain = (BlockchainImpl)worldManager.getBlockchain();
URL scenario1 = ClassLoader
.getSystemResource("blockload/scenario1.dmp");
File file = new File(scenario1.toURI());
List<String> strData = Files.readAllLines(file.toPath(), StandardCharsets.UTF_8);
byte[] root = Genesis.getInstance().getStateRoot();
for(String blockRLP : strData){
Block block = new Block(
Hex.decode(blockRLP));
logger.info("sending block.hash: {}", Hex.toHexString( block.getHash() ));
blockchain.tryToConnect(block);
root = block.getStateRoot();
}
logger.info("asserting root state is: {}", Hex.toHexString( root ));
//expected root: 13a5e615365c86438d98df5a2ca5bf1173ab4ea33be808fde7b94e47e9534549
assertArrayEquals(root, worldManager.getRepository().getRoot());
}
@Test
public void testScenario2() throws URISyntaxException, IOException {
BlockchainImpl blockchain = (BlockchainImpl)worldManager.getBlockchain();
URL scenario1 = ClassLoader
.getSystemResource("blockload/scenario2.dmp");
File file = new File(scenario1.toURI());
List<String> strData = Files.readAllLines(file.toPath(), StandardCharsets.UTF_8);
byte[] root = Genesis.getInstance().getStateRoot();
for(String blockRLP : strData){
Block block = new Block(
Hex.decode(blockRLP));
logger.info("sending block.hash: {}", Hex.toHexString( block.getHash() ));
blockchain.tryToConnect(block);
root = block.getStateRoot();
}
logger.info("asserting root state is: {}", Hex.toHexString( root ));
//expected root: 8bbff862199ccf5411c9505598eeba3d76b51e4d391ac1189903b0fcbdd3733b
assertArrayEquals(root, worldManager.getRepository().getRoot());
}
@Test
public void testScenario3() throws URISyntaxException, IOException {
BlockchainImpl blockchain = (BlockchainImpl)worldManager.getBlockchain();
URL scenario1 = ClassLoader
.getSystemResource("blockload/scenario3.dmp");
File file = new File(scenario1.toURI());
List<String> strData = Files.readAllLines(file.toPath(), StandardCharsets.UTF_8);
byte[] root = Genesis.getInstance().getStateRoot();
for(String blockRLP : strData){
Block block = new Block(
Hex.decode(blockRLP));
logger.info("sending block.hash: {}", Hex.toHexString( block.getHash() ));
blockchain.tryToConnect(block);
root = block.getStateRoot();
}
logger.info("asserting root state is: {}", Hex.toHexString( root ));
//expected root: 8bbff862199ccf5411c9505598eeba3d76b51e4d391ac1189903b0fcbdd3733b
assertArrayEquals(root, worldManager.getRepository().getRoot());
}
@Test
@Ignore
public void testUncleValidGenerationGap() {

View File

@ -68,10 +68,10 @@ public class ForkTest {
BlockchainImpl blockchain = (BlockchainImpl)worldManager.getBlockchain();
URL massiveUpload_1 = ClassLoader
URL scenario1 = ClassLoader
.getSystemResource("fork/scenario1.dmp");
File file = new File(massiveUpload_1.toURI());
File file = new File(scenario1.toURI());
List<String> strData = Files.readAllLines(file.toPath(), StandardCharsets.UTF_8);
for(String blockRLP : strData){
@ -96,10 +96,10 @@ public class ForkTest {
BlockchainImpl blockchain = (BlockchainImpl) worldManager.getBlockchain();
URL massiveUpload_1 = ClassLoader
URL scenario2 = ClassLoader
.getSystemResource("fork/scenario2.dmp");
File file = new File(massiveUpload_1.toURI());
File file = new File(scenario2.toURI());
List<String> strData = Files.readAllLines(file.toPath(), StandardCharsets.UTF_8);
for(String blockRLP : strData){

View File

@ -1,350 +1,559 @@
package test.ethereum.db;
import org.ethereum.config.SystemProperties;
import org.ethereum.core.AccountState;
import org.ethereum.db.RepositoryImpl;
import org.ethereum.core.Genesis;
import org.ethereum.facade.Repository;
import org.ethereum.manager.WorldManager;
import org.ethereum.db.RepositoryImpl;
import org.ethereum.vm.DataWord;
import org.junit.After;
import org.junit.FixMethodOrder;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.MethodSorters;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.spongycastle.util.encoders.Hex;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.support.AnnotationConfigContextLoader;
import test.ethereum.TestContext;
import java.math.BigInteger;
import static org.ethereum.crypto.HashUtil.EMPTY_DATA_HASH;
import static org.junit.Assert.*;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
/**
* www.ethereumJ.com
* www.etherj.com
*
* @author: Roman Mandeleil
* Created on: 23/06/2014 23:52
* Created on: 17/11/2014 23:08
*/
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(loader=AnnotationConfigContextLoader.class)
public class RepositoryTest {
private static final Logger logger = LoggerFactory.getLogger("test");
@Test
public void test1(){
SystemProperties.CONFIG.setDataBaseDir("test_db/"+ RepositoryTest.class);
Repository repository = new RepositoryImpl();
byte[] cow = Hex.decode("CD2A3D9F938E13CD947EC05ABC7FE734DF8DD826");
byte[] horse = Hex.decode("13978AEE95F38490E9769C39B2773ED763D9CD5F");
repository.increaseNonce(cow);
repository.increaseNonce(horse);
assertEquals(BigInteger.ONE, repository.getNonce(cow));
assertEquals(BigInteger.ONE, repository.getNonce(horse));
repository.close();
}
@Configuration
@ComponentScan(basePackages = "org.ethereum")
static class ContextConfiguration extends TestContext {
static {
SystemProperties.CONFIG.setDataBaseDir("test_db/"+ RepositoryTest.class);
@Test
public void test2(){
SystemProperties.CONFIG.setDataBaseDir("test_db/"+ RepositoryTest.class);
Repository repository = new RepositoryImpl();
byte[] cow = Hex.decode("CD2A3D9F938E13CD947EC05ABC7FE734DF8DD826");
byte[] horse = Hex.decode("13978AEE95F38490E9769C39B2773ED763D9CD5F");
repository.addBalance(cow, BigInteger.TEN);
repository.addBalance(horse, BigInteger.ONE);
assertEquals(BigInteger.TEN, repository.getBalance(cow));
assertEquals(BigInteger.ONE, repository.getBalance(horse));
repository.close();
}
@Test
public void test3(){
SystemProperties.CONFIG.setDataBaseDir("test_db/"+ RepositoryTest.class);
Repository repository = new RepositoryImpl();
byte[] cow = Hex.decode("CD2A3D9F938E13CD947EC05ABC7FE734DF8DD826");
byte[] horse = Hex.decode("13978AEE95F38490E9769C39B2773ED763D9CD5F");
byte[] cowCode = Hex.decode("A1A2A3");
byte[] horseCode = Hex.decode("B1B2B3");
repository.saveCode(cow, cowCode);
repository.saveCode(horse, horseCode);
assertArrayEquals(cowCode, repository.getCode(cow));
assertArrayEquals(horseCode, repository.getCode(horse));
repository.close();
}
@Test
public void test4(){
SystemProperties.CONFIG.setDataBaseDir("test_db/"+ RepositoryTest.class);
Repository repository = new RepositoryImpl();
byte[] cow = Hex.decode("CD2A3D9F938E13CD947EC05ABC7FE734DF8DD826");
byte[] horse = Hex.decode("13978AEE95F38490E9769C39B2773ED763D9CD5F");
byte[] cowKey = Hex.decode("A1A2A3");
byte[] cowValue = Hex.decode("A4A5A6");
byte[] horseKey = Hex.decode("B1B2B3");
byte[] horseValue = Hex.decode("B4B5B6");
repository.addStorageRow(cow, new DataWord(cowKey), new DataWord(cowValue));
repository.addStorageRow(horse, new DataWord(horseKey), new DataWord(horseValue));
assertEquals(new DataWord(cowValue), repository.getStorageValue(cow, new DataWord(cowKey)));
assertEquals(new DataWord(horseValue), repository.getStorageValue(horse, new DataWord(horseKey)));
repository.close();
}
@Test
public void test5(){
SystemProperties.CONFIG.setDataBaseDir("test_db/"+ RepositoryTest.class);
Repository repository = new RepositoryImpl();
Repository track = repository.startTracking();
byte[] cow = Hex.decode("CD2A3D9F938E13CD947EC05ABC7FE734DF8DD826");
byte[] horse = Hex.decode("13978AEE95F38490E9769C39B2773ED763D9CD5F");
track.increaseNonce(cow); track.increaseNonce(cow); track.increaseNonce(cow);
track.increaseNonce(cow); track.increaseNonce(cow); track.increaseNonce(cow);
track.increaseNonce(cow); track.increaseNonce(cow); track.increaseNonce(cow);
track.increaseNonce(cow);
track.increaseNonce(horse);
track.commit();
assertEquals(BigInteger.TEN, repository.getNonce(cow));
assertEquals(BigInteger.ONE, repository.getNonce(horse));
repository.close();
}
@Test
public void test6(){
SystemProperties.CONFIG.setDataBaseDir("test_db/"+ RepositoryTest.class);
Repository repository = new RepositoryImpl();
Repository track = repository.startTracking();
byte[] cow = Hex.decode("CD2A3D9F938E13CD947EC05ABC7FE734DF8DD826");
byte[] horse = Hex.decode("13978AEE95F38490E9769C39B2773ED763D9CD5F");
track.increaseNonce(cow); track.increaseNonce(cow); track.increaseNonce(cow);
track.increaseNonce(cow); track.increaseNonce(cow); track.increaseNonce(cow);
track.increaseNonce(cow); track.increaseNonce(cow); track.increaseNonce(cow);
track.increaseNonce(cow);
track.increaseNonce(horse);
assertEquals(BigInteger.TEN, track.getNonce(cow));
assertEquals(BigInteger.ONE, track.getNonce(horse));
track.rollback();
assertEquals(BigInteger.ZERO, repository.getNonce(cow));
assertEquals(BigInteger.ZERO, repository.getNonce(horse));
repository.close();
}
@Test
public void test7(){
SystemProperties.CONFIG.setDataBaseDir("test_db/"+ RepositoryTest.class);
Repository repository = new RepositoryImpl();
Repository track = repository.startTracking();
byte[] cow = Hex.decode("CD2A3D9F938E13CD947EC05ABC7FE734DF8DD826");
byte[] horse = Hex.decode("13978AEE95F38490E9769C39B2773ED763D9CD5F");
track.addBalance(cow, BigInteger.TEN);
track.addBalance(horse, BigInteger.ONE);
assertEquals(BigInteger.TEN, track.getBalance(cow));
assertEquals(BigInteger.ONE, track.getBalance(horse));
track.commit();
assertEquals(BigInteger.TEN, repository.getBalance(cow));
assertEquals(BigInteger.ONE, repository.getBalance(horse));
repository.close();
}
@Test
public void test8(){
SystemProperties.CONFIG.setDataBaseDir("test_db/"+ RepositoryTest.class);
Repository repository = new RepositoryImpl();
Repository track = repository.startTracking();
byte[] cow = Hex.decode("CD2A3D9F938E13CD947EC05ABC7FE734DF8DD826");
byte[] horse = Hex.decode("13978AEE95F38490E9769C39B2773ED763D9CD5F");
track.addBalance(cow, BigInteger.TEN);
track.addBalance(horse, BigInteger.ONE);
assertEquals(BigInteger.TEN, track.getBalance(cow));
assertEquals(BigInteger.ONE, track.getBalance(horse));
track.rollback();
assertEquals(BigInteger.ZERO, repository.getBalance(cow));
assertEquals(BigInteger.ZERO, repository.getBalance(horse));
repository.close();
}
@Test
public void test9(){
SystemProperties.CONFIG.setDataBaseDir("test_db/"+ RepositoryTest.class);
Repository repository = new RepositoryImpl();
Repository track = repository.startTracking();
byte[] cow = Hex.decode("CD2A3D9F938E13CD947EC05ABC7FE734DF8DD826");
byte[] horse = Hex.decode("13978AEE95F38490E9769C39B2773ED763D9CD5F");
DataWord cowKey = new DataWord(Hex.decode("A1A2A3"));
DataWord cowValue = new DataWord(Hex.decode("A4A5A6"));
DataWord horseKey = new DataWord(Hex.decode("B1B2B3"));
DataWord horseValue = new DataWord(Hex.decode("B4B5B6"));
track.addStorageRow(cow, cowKey, cowValue);
track.addStorageRow(horse, horseKey, horseValue);
assertEquals(cowValue, track.getStorageValue(cow, cowKey));
assertEquals(horseValue, track.getStorageValue(horse, horseKey));
track.commit();
assertEquals(cowValue, repository.getStorageValue(cow, cowKey));
assertEquals(horseValue, repository.getStorageValue(horse, horseKey));
repository.close();
}
@Test
public void test10(){
SystemProperties.CONFIG.setDataBaseDir("test_db/"+ RepositoryTest.class);
Repository repository = new RepositoryImpl();
Repository track = repository.startTracking();
byte[] cow = Hex.decode("CD2A3D9F938E13CD947EC05ABC7FE734DF8DD826");
byte[] horse = Hex.decode("13978AEE95F38490E9769C39B2773ED763D9CD5F");
DataWord cowKey = new DataWord(Hex.decode("A1A2A3"));
DataWord cowValue = new DataWord(Hex.decode("A4A5A6"));
DataWord horseKey = new DataWord(Hex.decode("B1B2B3"));
DataWord horseValue = new DataWord(Hex.decode("B4B5B6"));
track.addStorageRow(cow, cowKey, cowValue);
track.addStorageRow(horse, horseKey, horseValue);
assertEquals(cowValue, track.getStorageValue(cow, cowKey));
assertEquals(horseValue, track.getStorageValue(horse, horseKey));
track.rollback();
assertEquals(null, repository.getStorageValue(cow, cowKey));
assertEquals(null, repository.getStorageValue(horse, horseKey));
repository.close();
}
@Test
public void test11(){
SystemProperties.CONFIG.setDataBaseDir("test_db/"+ RepositoryTest.class);
Repository repository = new RepositoryImpl();
Repository track = repository.startTracking();
byte[] cow = Hex.decode("CD2A3D9F938E13CD947EC05ABC7FE734DF8DD826");
byte[] horse = Hex.decode("13978AEE95F38490E9769C39B2773ED763D9CD5F");
byte[] cowCode = Hex.decode("A1A2A3");
byte[] horseCode = Hex.decode("B1B2B3");
track.saveCode(cow, cowCode);
track.saveCode(horse, horseCode);
assertArrayEquals(cowCode, track.getCode(cow));
assertArrayEquals(horseCode, track.getCode(horse));
track.commit();
assertArrayEquals(cowCode, repository.getCode(cow));
assertArrayEquals(horseCode, repository.getCode(horse));
repository.close();
}
@Test
public void test12(){
SystemProperties.CONFIG.setDataBaseDir("test_db/"+ RepositoryTest.class);
Repository repository = new RepositoryImpl();
Repository track = repository.startTracking();
byte[] cow = Hex.decode("CD2A3D9F938E13CD947EC05ABC7FE734DF8DD826");
byte[] horse = Hex.decode("13978AEE95F38490E9769C39B2773ED763D9CD5F");
byte[] cowCode = Hex.decode("A1A2A3");
byte[] horseCode = Hex.decode("B1B2B3");
track.saveCode(cow, cowCode);
track.saveCode(horse, horseCode);
assertArrayEquals(cowCode, track.getCode(cow));
assertArrayEquals(horseCode, track.getCode(horse));
track.rollback();
assertArrayEquals(null, repository.getCode(cow));
assertArrayEquals(null, repository.getCode(horse));
repository.close();
}
@Test // Let's upload genesis pre-mine just like in the real world
public void test13(){
SystemProperties.CONFIG.setDataBaseDir("test_db/"+ RepositoryTest.class);
Repository repository = new RepositoryImpl();
Repository track = repository.startTracking();
for (String address : Genesis.getPremine()) {
track.addBalance(Hex.decode(address), Genesis.PREMINE_AMOUNT);
}
}
@Autowired
WorldManager worldManager;
track.commit();
@After
public void doReset(){
worldManager.reset();
assertArrayEquals(Genesis.getInstance().getStateRoot(), repository.getRoot());
repository.close();
}
@Test // create account, get account
public void test1() {
@Test
public void test14(){
String addr = "cd2a3d9f938e13cd947ec05abc7fe734df8dd826";
Repository repository = worldManager.getRepository();
SystemProperties.CONFIG.setDataBaseDir("test_db/"+ RepositoryTest.class);
Repository repository = new RepositoryImpl();
AccountState createdState = repository.createAccount(Hex.decode(addr));
AccountState fetchedState = repository.getAccountState(Hex.decode(addr));
assertEquals(createdState.getEncoded(), fetchedState.getEncoded());
}
byte[] cow = Hex.decode("CD2A3D9F938E13CD947EC05ABC7FE734DF8DD826");
byte[] horse = Hex.decode("13978AEE95F38490E9769C39B2773ED763D9CD5F");
final BigInteger ELEVEN = BigInteger.TEN.add(BigInteger.ONE);
@Test // increase nonce
public void test2() {
// changes level_1
Repository track1 = repository.startTracking();
track1.addBalance(cow, BigInteger.TEN);
track1.addBalance(horse, BigInteger.ONE);
String addr = "cd2a3d9f938e13cd947ec05abc7fe734df8dd826";
Repository repository = worldManager.getRepository();
assertEquals(BigInteger.TEN, track1.getBalance(cow));
assertEquals(BigInteger.ONE, track1.getBalance(horse));
BigInteger nonce0 = repository.getNonce(Hex.decode(addr));
repository.createAccount(Hex.decode(addr));
BigInteger nonce1 = repository.getNonce(Hex.decode(addr));
// changes level_2
Repository track2 = track1.startTracking();
track2.addBalance(cow, BigInteger.ONE);
track2.addBalance(horse, BigInteger.TEN);
repository.increaseNonce(Hex.decode(addr));
BigInteger nonce2 = repository.getNonce(Hex.decode(addr));
assertEquals(ELEVEN, track2.getBalance(cow));
assertEquals(ELEVEN, track2.getBalance(horse));
assertEquals(0, nonce0.intValue());
assertEquals(0, nonce1.intValue());
assertEquals(1, nonce2.intValue());
track2.commit();
track1.commit();
assertEquals(ELEVEN, repository.getBalance(cow));
assertEquals(ELEVEN, repository.getBalance(horse));
repository.close();
}
@Test // increase nonce
public void test3() {
String addr = "cd2a3d9f938e13cd947ec05abc7fe734df8dd826";
Repository repository = worldManager.getRepository();
@Test
public void test15(){
BigInteger nonce0 = repository.getNonce(Hex.decode(addr));
SystemProperties.CONFIG.setDataBaseDir("test_db/"+ RepositoryTest.class);
Repository repository = new RepositoryImpl();
repository.createAccount(Hex.decode(addr));
BigInteger nonce1 = repository.getNonce(Hex.decode(addr));
byte[] cow = Hex.decode("CD2A3D9F938E13CD947EC05ABC7FE734DF8DD826");
byte[] horse = Hex.decode("13978AEE95F38490E9769C39B2773ED763D9CD5F");
final BigInteger ELEVEN = BigInteger.TEN.add(BigInteger.ONE);
repository.increaseNonce(Hex.decode(addr));
repository.increaseNonce(Hex.decode(addr));
repository.increaseNonce(Hex.decode(addr));
BigInteger nonce2 = repository.getNonce(Hex.decode(addr));
assertEquals(0, nonce0.intValue());
assertEquals(0, nonce1.intValue());
assertEquals(3, nonce2.intValue());
// changes level_1
Repository track1 = repository.startTracking();
track1.addBalance(cow, BigInteger.TEN);
track1.addBalance(horse, BigInteger.ONE);
assertEquals(BigInteger.TEN, track1.getBalance(cow));
assertEquals(BigInteger.ONE, track1.getBalance(horse));
// changes level_2
Repository track2 = track1.startTracking();
track2.addBalance(cow, BigInteger.ONE);
track2.addBalance(horse, BigInteger.TEN);
assertEquals(ELEVEN, track2.getBalance(cow));
assertEquals(ELEVEN, track2.getBalance(horse));
track2.rollback();
track1.commit();
assertEquals(BigInteger.TEN, repository.getBalance(cow));
assertEquals(BigInteger.ONE, repository.getBalance(horse));
repository.close();
}
@Test // change balance
public void test4() {
String addr = "cd2a3d9f938e13cd947ec05abc7fe734df8dd826";
Repository repository = worldManager.getRepository();
@Test
public void test16(){
BigInteger balance0 = repository.getBalance(Hex.decode(addr));
SystemProperties.CONFIG.setDataBaseDir("test_db/"+ RepositoryTest.class);
Repository repository = new RepositoryImpl();
repository.createAccount(Hex.decode(addr));
BigInteger balance1 = repository.getBalance(Hex.decode(addr));
byte[] cow = Hex.decode("CD2A3D9F938E13CD947EC05ABC7FE734DF8DD826");
byte[] horse = Hex.decode("13978AEE95F38490E9769C39B2773ED763D9CD5F");
repository.addBalance(Hex.decode(addr), BigInteger.valueOf(300));
BigInteger balance2 = repository.getBalance(Hex.decode(addr));
byte[] cowKey1 = "key-c-1".getBytes();
byte[] cowValue1 = "val-c-1".getBytes();
assertEquals(0, balance0.intValue());
assertEquals(0, balance1.intValue());
assertEquals(300, balance2.intValue());
byte[] horseKey1 = "key-h-1".getBytes();
byte[] horseValue1 = "val-h-1".getBytes();
byte[] cowKey2 = "key-c-2".getBytes();
byte[] cowValue2 = "val-c-2".getBytes();
byte[] horseKey2 = "key-h-2".getBytes();
byte[] horseValue2 = "val-h-2".getBytes();
// changes level_1
Repository track1 = repository.startTracking();
track1.addStorageRow(cow, new DataWord(cowKey1), new DataWord(cowValue1));
track1.addStorageRow(horse, new DataWord(horseKey1), new DataWord(horseValue1));
assertEquals(new DataWord(cowValue1), track1.getStorageValue(cow, new DataWord(cowKey1)));
assertEquals(new DataWord(horseValue1), track1.getStorageValue(horse, new DataWord(horseKey1)));
// changes level_2
Repository track2 = track1.startTracking();
track2.addStorageRow(cow, new DataWord(cowKey2), new DataWord(cowValue2));
track2.addStorageRow(horse, new DataWord(horseKey2), new DataWord(horseValue2));
assertEquals(new DataWord(cowValue1), track2.getStorageValue(cow, new DataWord(cowKey1)));
assertEquals(new DataWord(horseValue1), track2.getStorageValue(horse, new DataWord(horseKey1)));
assertEquals(new DataWord(cowValue2), track2.getStorageValue(cow, new DataWord(cowKey2)));
assertEquals(new DataWord(horseValue2), track2.getStorageValue(horse, new DataWord(horseKey2)));
track2.commit();
// leaving level_2
assertEquals(new DataWord(cowValue1), track1.getStorageValue(cow, new DataWord(cowKey1)));
assertEquals(new DataWord(horseValue1), track1.getStorageValue(horse, new DataWord(horseKey1)));
assertEquals(new DataWord(cowValue2), track1.getStorageValue(cow, new DataWord(cowKey2)));
assertEquals(new DataWord(horseValue2), track1.getStorageValue(horse, new DataWord(horseKey2)));
track1.commit();
// leaving level_1
assertEquals(new DataWord(cowValue1), repository.getStorageValue(cow, new DataWord(cowKey1)));
assertEquals(new DataWord(horseValue1), repository.getStorageValue(horse, new DataWord(horseKey1)));
assertEquals(new DataWord(cowValue2), repository.getStorageValue(cow, new DataWord(cowKey2)));
assertEquals(new DataWord(horseValue2), repository.getStorageValue(horse, new DataWord(horseKey2)));
repository.close();
}
@Test // change balance
public void test5() {
String addr = "cd2a3d9f938e13cd947ec05abc7fe734df8dd826";
Repository repository = worldManager.getRepository();
@Test
public void test17(){
BigInteger balance0 = repository.getBalance(Hex.decode(addr));
SystemProperties.CONFIG.setDataBaseDir("test_db/"+ RepositoryTest.class);
Repository repository = new RepositoryImpl();
repository.createAccount(Hex.decode(addr));
BigInteger balance1 = repository.getBalance(Hex.decode(addr));
byte[] cow = Hex.decode("CD2A3D9F938E13CD947EC05ABC7FE734DF8DD826");
byte[] horse = Hex.decode("13978AEE95F38490E9769C39B2773ED763D9CD5F");
final BigInteger ELEVEN = BigInteger.TEN.add(BigInteger.ONE);
repository.addBalance(Hex.decode(addr), BigInteger.valueOf(300));
BigInteger balance2 = repository.getBalance(Hex.decode(addr));
byte[] cowKey1 = "key-c-1".getBytes();
byte[] cowValue1 = "val-c-1".getBytes();
repository.addBalance(Hex.decode(addr), BigInteger.valueOf(-150));
BigInteger balance3 = repository.getBalance(Hex.decode(addr));
byte[] horseKey1 = "key-h-1".getBytes();
byte[] horseValue1 = "val-h-1".getBytes();
assertEquals(0, balance0.intValue());
assertEquals(0, balance1.intValue());
assertEquals(300, balance2.intValue());
assertEquals(150, balance3.intValue());
byte[] cowKey2 = "key-c-2".getBytes();
byte[] cowValue2 = "val-c-2".getBytes();
byte[] horseKey2 = "key-h-2".getBytes();
byte[] horseValue2 = "val-h-2".getBytes();
// changes level_1
Repository track1 = repository.startTracking();
track1.addStorageRow(cow, new DataWord(cowKey1), new DataWord(cowValue1));
track1.addStorageRow(horse, new DataWord(horseKey1), new DataWord(horseValue1));
assertEquals(new DataWord(cowValue1), track1.getStorageValue(cow, new DataWord(cowKey1)));
assertEquals(new DataWord(horseValue1), track1.getStorageValue(horse, new DataWord(horseKey1)));
// changes level_2
Repository track2 = track1.startTracking();
track2.addStorageRow(cow, new DataWord(cowKey2), new DataWord(cowValue2));
track2.addStorageRow(horse, new DataWord(horseKey2), new DataWord(horseValue2));
assertEquals(new DataWord(cowValue1), track2.getStorageValue(cow, new DataWord(cowKey1)));
assertEquals(new DataWord(horseValue1), track2.getStorageValue(horse, new DataWord(horseKey1)));
assertEquals(new DataWord(cowValue2), track2.getStorageValue(cow, new DataWord(cowKey2)));
assertEquals(new DataWord(horseValue2), track2.getStorageValue(horse, new DataWord(horseKey2)));
track2.rollback();
// leaving level_2
assertEquals(new DataWord(cowValue1), track1.getStorageValue(cow, new DataWord(cowKey1)));
assertEquals(new DataWord(horseValue1), track1.getStorageValue(horse, new DataWord(horseKey1)));
assertNull(track1.getStorageValue(cow, new DataWord(cowKey2)));
assertNull(track1.getStorageValue(horse, new DataWord(horseKey2)));
track1.commit();
// leaving level_1
assertEquals(new DataWord(cowValue1), repository.getStorageValue(cow, new DataWord(cowKey1)));
assertEquals(new DataWord(horseValue1), repository.getStorageValue(horse, new DataWord(horseKey1)));
assertNull(repository.getStorageValue(cow, new DataWord(cowKey2)));
assertNull(repository.getStorageValue(horse, new DataWord(horseKey2)));
repository.close();
}
@Test // get/set code
public void test6() {
String addr = "cd2a3d9f938e13cd947ec05abc7fe734df8dd826";
Repository repository = worldManager.getRepository();
@Test
public void test18(){
byte[] code = repository.getCode(Hex.decode(addr));
assertTrue(code == null);
}
@Test // get/set code
public void test7() {
String addr = "cd2a3d9f938e13cd947ec05abc7fe734df8dd826";
String codeString = "7f60c860005461012c602054000000000000000000000000000000000000000000600060206000f200";
String codeHash = "8f0d7fc8cc6fdd688fa58ae9256310069f5659ed2a8a3af994d80350fbf1e798";
Repository repository = worldManager.getRepository();
byte[] code0 = repository.getCode(Hex.decode(addr));
repository.createAccount(Hex.decode(addr));
repository.saveCode(Hex.decode(addr), Hex.decode(codeString));
byte[] code1 = repository.getCode(Hex.decode(addr));
AccountState accountState = repository.getAccountState(Hex.decode(addr));
assertTrue(code0 == null);
assertEquals(codeString, Hex.toHexString(code1));
assertEquals(codeHash, Hex.toHexString(accountState.getCodeHash()));
}
@Test // get/set code
public void test8() {
byte[] addr = Hex.decode("cd2a3d9f938e13cd947ec05abc7fe734df8dd826");
Repository repository = worldManager.getRepository();
byte[] code0 = repository.getCode(addr);
repository.createAccount(addr);
byte[] code1 = repository.getCode(addr);
AccountState accountState = repository.getAccountState(addr);
assertTrue(code0 == null);
assertNull(code1);
assertArrayEquals(EMPTY_DATA_HASH, accountState.getCodeHash());
}
@Test // storage set/get
public void test9() {
String addr = "cd2a3d9f938e13cd947ec05abc7fe734df8dd826";
byte[] keyBytes = Hex.decode("c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470");
DataWord key = new DataWord(keyBytes);
Repository repository = worldManager.getRepository();
DataWord value = repository.getStorageValue(Hex.decode(addr), key);
assertNull(value);
}
@Test // storage set/get
public void test10() {
byte[] addr = Hex.decode("cd2a3d9f938e13cd947ec05abc7fe734df8dd826");
byte[] code = Hex.decode("00");
Repository repository = worldManager.getRepository();
repository.createAccount(addr);
repository.saveCode(addr, code);
byte[] keyBytes = Hex.decode("cd2a3d9f938e13cd947ec05abc7fe734df8dd826");
DataWord key = new DataWord(keyBytes);
byte[] valueBytes = Hex.decode("0F4240");
DataWord value = new DataWord(valueBytes);
repository.addStorageRow(addr, key, value);
DataWord fetchedValue = repository.getStorageValue(addr, key);
assertEquals(value, fetchedValue);
}
@Test // storage set/get
public void test11() {
byte[] addr = Hex.decode("cd2a3d9f938e13cd947ec05abc7fe734df8dd826");
byte[] code = Hex.decode("00");
String expectedStorageHash = "a737c40a4aa895fb9eb464536c376ee7c2c08eb733c8fd2353fcc62dc734f075";
Repository repository = worldManager.getRepository();
repository.createAccount(addr);
repository.saveCode(addr, code);
byte[] keyBytes = Hex.decode("03E8");
DataWord key1 = new DataWord(keyBytes);
keyBytes = Hex.decode("03E9");
DataWord key2 = new DataWord(keyBytes);
keyBytes = Hex.decode("03F0");
DataWord key3 = new DataWord(keyBytes);
byte[] valueBytes = Hex.decode("0F4240");
DataWord value1 = new DataWord(valueBytes);
valueBytes = Hex.decode("0F4241");
DataWord value2 = new DataWord(valueBytes);
valueBytes = Hex.decode("0F4242");
DataWord value3 = new DataWord(valueBytes);
repository.addStorageRow(addr, key1, value1);
repository.addStorageRow(addr, key2, value2);
repository.addStorageRow(addr, key3, value3);
DataWord fetchedValue1 = repository.getStorageValue(addr, key1);
DataWord fetchedValue2 = repository.getStorageValue(addr, key2);
DataWord fetchedValue3 = repository.getStorageValue(addr, key3);
AccountState accountState = repository.getAccountState(addr);
String stateRoot = Hex.toHexString(accountState.getStateRoot());
assertEquals(value1, fetchedValue1);
assertEquals(value2, fetchedValue2);
assertEquals(value3, fetchedValue3);
assertEquals(expectedStorageHash, stateRoot);
}
@Test // commit/rollback
public void test12() {
String addr = "cd2a3d9f938e13cd947ec05abc7fe734df8dd826";
long expectedBalance = 333;
Repository origRepository = worldManager.getRepository();
Repository repository = origRepository.getTrack();
repository.startTracking();
repository.createAccount(Hex.decode(addr));
repository.addBalance(Hex.decode(addr), BigInteger.valueOf(expectedBalance));
repository.commit();
BigInteger balance = repository.getBalance(Hex.decode(addr));
assertEquals(expectedBalance, balance.longValue());
}
@Test // commit/rollback
public void test13() {
String addr = "cd2a3d9f938e13cd947ec05abc7fe734df8dd826";
long expectedBalance_1 = 55500;
long expectedBalance_2 = 0;
Repository origRepository = worldManager.getRepository();
Repository repository = origRepository.getTrack();
repository.startTracking();
repository.createAccount(Hex.decode(addr));
repository.addBalance(Hex.decode(addr), BigInteger.valueOf(55500));
BigInteger balance = repository.getBalance(Hex.decode(addr));
assertEquals(expectedBalance_1, balance.longValue());
repository.rollback();
balance = repository.getBalance(Hex.decode(addr));
assertEquals(expectedBalance_2, balance.longValue());
}
@Test // commit/rollback
public void test14() {
String addr_1 = "cd2a3d9f938e13cd947ec05abc7fe734df8dd826";
String addr_2 = "77045e71a7a2c50903d88e564cd72fab11e82051";
String codeString = "7f60c860005461012c602054000000000000000000000000000000000000000000600060206000f200";
long expectedBalance = 55500;
Repository origRepository = worldManager.getRepository();
Repository repository = origRepository.getTrack();
repository.createAccount(Hex.decode(addr_1));
repository.addBalance(Hex.decode(addr_1), BigInteger.valueOf(expectedBalance));
repository.startTracking();
repository.createAccount(Hex.decode(addr_2));
repository.saveCode(Hex.decode(addr_2), Hex.decode(codeString));
repository.addStorageRow(Hex.decode(addr_2), new DataWord(101), new DataWord(1000001));
repository.addStorageRow(Hex.decode(addr_2), new DataWord(102), new DataWord(1000002));
repository.addStorageRow(Hex.decode(addr_2), new DataWord(103), new DataWord(1000003));
repository.rollback();
BigInteger balance = repository.getBalance(Hex.decode(addr_1));
assertEquals(expectedBalance, balance.longValue());
DataWord value = repository.getStorageValue(Hex.decode(addr_2), new DataWord(101));
assertNull(value);
}
}

View File

@ -0,0 +1,3 @@
f90139f90134a0955f36d073ccb026b78ab3424c15cf966a7563aa270413859f78702b9e8e22cba01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347949d6327e4f16d48a3e4b658503d9e3256293fce75a045c8c6675b11d66a33e351d2f104830727c909b58061cf992e85d622e33962e5a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b840000000000000000000000000000080000000000000100000000000000000400000000000000000000000000000000000000000000000000000000000000000008301ff80018609184e72a000830f3e6f80845466342180a0b8605c26e6d37aac4986bd952f36b6f595e96d76fec99eee832af740e454f42ac0c0
f90139f90134a0dc24d5c43ad451400404f9255b7f63bdceeb11310a2b9ece302626cda9b41ff7a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347949d6327e4f16d48a3e4b658503d9e3256293fce75a05c2fcc83b43e09eee6801174a2db881187fbbdaf51e201350ec5009f8231e389a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b840000000000000000000000000000080000000000000100000000000000000400000000000000000000000000000000000000000000000000000000000000000008301ffff028609184e72a000830f3a9f80845466342180a090649c06424d4ba8462bcb50b4dcd8507931366e8a5f8cd61019ae590872523bc0c0
f9020af90136a007bc19da9a5ecc987f579f40d1c450bd1d9938983929dce31d0a0734f76798a5a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347949d6327e4f16d48a3e4b658503d9e3256293fce75a013a5e615365c86438d98df5a2ca5bf1173ab4ea33be808fde7b94e47e9534549a00ddba1aad325f4f6d24e0b50ff6ceb3282650ccedc7afacbaa1256e18e014a55a072170d776433bd79dbbb1793f3cb1105ac369da0b142103639df7696e9718016b840000000000000000000000000000080000000000000100000000000000000400000000000000000000000000000000000000000000000000000000000000000008301ff80038609184e72a000830f36d08203e8845466342a80a086862224f20522063b12624e1c1158fc936bd549ca632e780d08471806bed945f8cef865808609184e72a0008203e894885f93eed577f2fc341ebb9a5c9b2ce4465d96c40c801ca01377aa9363574f78d328844287690b4ba7b96dbc9d2a12c67fc60c821093b3a3a06385f6507e8314e45c6b79536ffd164bc8f87d24c63a832c41ce444492101887f865018609184e72a0008203e894885f93eed577f2fc341ebb9a5c9b2ce4465d96c40c801ca062f64877aa71aa94bdddfa9c12be8aab35278f8856e1940aa2a55caf431152fea0101275c02e8b76c28f6cf90ed3a2dde0160eaba021a00cbfd02d1496b7d274fbc0

View File

@ -0,0 +1,4 @@
f90139f90134a0955f36d073ccb026b78ab3424c15cf966a7563aa270413859f78702b9e8e22cba01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347949d6327e4f16d48a3e4b658503d9e3256293fce75a045c8c6675b11d66a33e351d2f104830727c909b58061cf992e85d622e33962e5a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b840000000000000000000000000000080000000000000100000000000000000400000000000000000000000000000000000000000000000000000000000000000008301ff80018609184e72a000830f3e6f80845466342180a0b8605c26e6d37aac4986bd952f36b6f595e96d76fec99eee832af740e454f42ac0c0
f90139f90134a0dc24d5c43ad451400404f9255b7f63bdceeb11310a2b9ece302626cda9b41ff7a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347949d6327e4f16d48a3e4b658503d9e3256293fce75a05c2fcc83b43e09eee6801174a2db881187fbbdaf51e201350ec5009f8231e389a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b840000000000000000000000000000080000000000000100000000000000000400000000000000000000000000000000000000000000000000000000000000000008301ffff028609184e72a000830f3a9f80845466342180a090649c06424d4ba8462bcb50b4dcd8507931366e8a5f8cd61019ae590872523bc0c0
f9020af90136a007bc19da9a5ecc987f579f40d1c450bd1d9938983929dce31d0a0734f76798a5a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347949d6327e4f16d48a3e4b658503d9e3256293fce75a013a5e615365c86438d98df5a2ca5bf1173ab4ea33be808fde7b94e47e9534549a00ddba1aad325f4f6d24e0b50ff6ceb3282650ccedc7afacbaa1256e18e014a55a072170d776433bd79dbbb1793f3cb1105ac369da0b142103639df7696e9718016b840000000000000000000000000000080000000000000100000000000000000400000000000000000000000000000000000000000000000000000000000000000008301ff80038609184e72a000830f36d08203e8845466342a80a086862224f20522063b12624e1c1158fc936bd549ca632e780d08471806bed945f8cef865808609184e72a0008203e894885f93eed577f2fc341ebb9a5c9b2ce4465d96c40c801ca01377aa9363574f78d328844287690b4ba7b96dbc9d2a12c67fc60c821093b3a3a06385f6507e8314e45c6b79536ffd164bc8f87d24c63a832c41ce444492101887f865018609184e72a0008203e894885f93eed577f2fc341ebb9a5c9b2ce4465d96c40c801ca062f64877aa71aa94bdddfa9c12be8aab35278f8856e1940aa2a55caf431152fea0101275c02e8b76c28f6cf90ed3a2dde0160eaba021a00cbfd02d1496b7d274fbc0
f90272f90136a0317604546eb502cf91b3d142301de66d46385fa3e89d6994bf8ed04e32a7ae55a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347949d6327e4f16d48a3e4b658503d9e3256293fce75a08bbff862199ccf5411c9505598eeba3d76b51e4d391ac1189903b0fcbdd3733ba0ae62cdf41908bd8593c9065b34653bdbebeeb5bd372e4f82b8afb9178dd0c843a0ee823bbd7016023e00804ae726cfe8c611e7ceeeb64644a96aaa77e4c868f3c4b840000000000000000000000000000080000000000000100000000000000000400000000000000000000000000000000000000000000000000000000000000000008301ff01048609184e72a000830f33038205dc845466346080a0a5f179dd5b8af29bd95c139af1a57815548669b6cd470485bea03088612c4c1cf90135f865028609184e72a0008203e894885f93eed577f2fc341ebb9a5c9b2ce4465d96c40c801ba02891f3a500f4639906fdebb99cfad59c8f3fda9ed9d4ac13c40f01bedf38cfeea03ea2c3ce1b5346fe803c2e00309cc324979da38fac6893f182fc2a70d6d354d0f865038609184e72a0008203e894885f93eed577f2fc341ebb9a5c9b2ce4465d96c40c801ba0e0b83b97cad39259c8d9c73125036b794025bf129b9718f16e2c95892c84f3b3a02cf5bfd58c73043eb6b8d23d0a8d762e5a33e68d964a0b078efb36c7fbb78ebff865048609184e72a0008203e894885f93eed577f2fc341ebb9a5c9b2ce4465d96c40c801ca0c2586f90246d16d1d19c5b2ecc73c64f7d2028367122ec4c4d38e37850bd22aca045021f7342e69f07e4d6f28ad0075105596e6f4b38e3c1d3905d7d16162fc9f8c0

File diff suppressed because one or more lines are too long

View File

@ -5,7 +5,7 @@ log4j.rootLogger=DEBUG, stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern= %d{HH:mm:ss} [%c{1}] %m%n
log4j.appender.stdout.layout.ConversionPattern= %d{HH:mm:ss.SSS} [%c{1}] %m%n
# filter noisy classes
log4j.logger.block = ERROR

View File

@ -71,7 +71,7 @@
<dependency>
<groupId>org.ethereum</groupId>
<artifactId>ethereumj</artifactId>
<version>0.7.9.20141116.1409</version>
<version>0.7.9.20141119.1233</version>
</dependency>