New Repositroy management:

+ Included and refactored all the repository usage
+ VMTest all pass
+ VMComplex test except 4 all pass
- The rootState of the blcok need sollution
- The contract create contract test VMComplexTest 4 need recheck
This commit is contained in:
romanman 2014-06-24 23:53:19 +01:00
parent 9d650350f0
commit 415f87c727
19 changed files with 482 additions and 768 deletions

View File

@ -71,7 +71,11 @@ public class Block {
difficulty, number, minGasPrice, gasLimit, gasUsed,
timestamp, extraData, nonce);
this.txsState = new Trie(null);
this.header.setStateRoot(WorldManager.instance.worldState.getRootHash());
// TODO: REFACTOR REPOSITORY TO GET ROOT HASH FOR HERE
// TODO: REFACTOR REPOSITORY TO GET ROOT HASH FOR HERE
// TODO: REFACTOR REPOSITORY TO GET ROOT HASH FOR HERE
this.header.setStateRoot(null);
this.header.setTxTrieRoot(txsState.getRootHash());
this.transactionsList = transactionsList;
this.uncleList = uncleList;
@ -197,7 +201,7 @@ public class Block {
public List<Transaction> getTransactionsList() {
if (!parsed) parseRLP();
if (transactionsList == null) {
this.transactionsList = new ArrayList<Transaction>();
this.transactionsList = new ArrayList<>();
}
return transactionsList;
}
@ -205,7 +209,7 @@ public class Block {
public List<TransactionReceipt> getTxReceiptList() {
if (!parsed) parseRLP();
if (transactionsList == null) {
this.txReceiptList = new ArrayList<TransactionReceipt>();
this.txReceiptList = new ArrayList<>();
}
return txReceiptList;
}
@ -213,7 +217,7 @@ public class Block {
public List<Block> getUncleList() {
if (!parsed) parseRLP();
if (uncleList == null) {
this.uncleList = new ArrayList<Block>();
this.uncleList = new ArrayList<>();
}
return uncleList;
}
@ -299,14 +303,6 @@ public class Block {
// this.allAccountsState.update();
}
public byte[] updateState(byte[] key, byte[] value) {
WorldManager.instance.worldState.update(key, value);
byte[] stateRoot = WorldManager.instance.worldState.getRootHash();
this.header.setStateRoot(stateRoot);
return stateRoot;
}
/**
* This mechanism enforces a homeostasis in terms of the time between blocks;
* a smaller period between the last two blocks results in an increase in the
@ -320,7 +316,6 @@ public class Block {
if(!this.isGenesis()) {
// verify difficulty meets requirements
isValid = this.getDifficulty() == this.calcDifficulty();
// verify nonce meest difficulty requirements
isValid = this.validateNonce();
// verify gasLimit meets requirements
isValid = this.getGasLimit() == this.calcGasLimit();
@ -367,9 +362,6 @@ public class Block {
/**
* Verify that block is valid for its difficulty
*
* @param block
* @param difficulty
* @param testNonce
* @return
*/
public boolean validateNonce() {

View File

@ -1,106 +0,0 @@
package org.ethereum.core;
import org.ethereum.util.RLP;
import org.ethereum.util.RLPElement;
import org.ethereum.util.RLPItem;
import org.ethereum.util.RLPList;
import org.ethereum.vm.DataWord;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* www.ethereumJ.com
*
* @author: Roman Mandeleil
* Created on: 09/06/2014 15:31
*/
public class ContractDetails {
private byte[] rlpEncoded;
List<DataWord> storageKeys;
List<DataWord> storageValues;
public ContractDetails(byte[] rlpEncoded) {
RLPList data = RLP.decode2(rlpEncoded);
RLPList rlpList = (RLPList)data.get(0);
RLPList keys = (RLPList)rlpList.get(0);
RLPList values = (RLPList)rlpList.get(1);
if (keys.size() > 0){
storageKeys = new ArrayList<>();
storageValues = new ArrayList<>();
}
for (int i = 0; i < keys.size(); ++i){
RLPItem rlpItem = (RLPItem)keys.get(i);
storageKeys.add(new DataWord(rlpItem.getRLPData()));
}
for (int i = 0; i < values.size(); ++i){
RLPItem rlpItem = (RLPItem)values.get(i);
storageValues.add(new DataWord(rlpItem.getRLPData()));
}
}
public ContractDetails(Map<DataWord, DataWord> storage) {
storageKeys = new ArrayList<DataWord>();
storageValues = new ArrayList<DataWord>();
for(DataWord key : storage.keySet()){
DataWord value = storage.get(key);
storageKeys.add(key);
storageValues.add(value);
}
}
public byte[] getEncoded() {
if(rlpEncoded == null) {
byte[][] keys = new byte[storageKeys.size()][];
byte[][] values = new byte[storageValues.size()][];
int i = 0;
for (DataWord key : storageKeys){
keys[i] = RLP.encodeElement( key.getData());
++i;
}
i = 0;
for (DataWord value : storageValues){
values[i] = RLP.encodeElement( value.getData() );
++i;
}
byte[] rlpKeysList = RLP.encodeList(keys);
byte[] rlpValuesList = RLP.encodeList(values);
this.rlpEncoded = RLP.encodeList(rlpKeysList, rlpValuesList);
}
return rlpEncoded;
}
public Map<DataWord, DataWord> getStorage(){
Map<DataWord, DataWord> storage = new HashMap<>();
for (int i = 0;
storageKeys != null &&
i < storageKeys.size(); ++i){
storage.put(storageKeys.get(i), storageValues.get(i));
}
return storage;
}
}

View File

@ -3,6 +3,7 @@ package org.ethereum.core;
import java.math.BigInteger;
import org.ethereum.crypto.HashUtil;
import org.ethereum.manager.WorldManager;
import org.ethereum.util.RLP;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -69,8 +70,9 @@ public class Genesis extends Block {
// Premine state
for (String address : premine) {
this.updateState(Hex.decode(address), acct.getEncoded());
}
WorldManager.instance.repository.createAccount(Hex.decode(address));
WorldManager.instance.repository.addBalance(Hex.decode(address), BigInteger.valueOf(2).pow(200) );
}
logger.info("Genesis-hash: " + Hex.toHexString(this.getHash()));
logger.info("Genesis-stateRoot: " + Hex.toHexString(this.getStateRoot()));
}

View File

@ -17,7 +17,7 @@ import java.util.*;
* Created on: 24/06/2014 00:12
*/
public class NewContractDetails {
public class ContractDetails {
private byte[] rlpEncoded;
@ -29,18 +29,27 @@ public class NewContractDetails {
Trie storageTrie = new Trie(null);
public NewContractDetails(){}
public NewContractDetails(byte[] rlpCode) {
public ContractDetails(){}
public ContractDetails(byte[] rlpCode) {
decode(rlpCode);
}
public NewContractDetails(Map<DataWord, DataWord> storage, byte[] code) {}
public ContractDetails(Map<DataWord, DataWord> storage, byte[] code) {}
public void put(DataWord key, DataWord value){
storageTrie.update(key.getData(), value.getData());
int index = storageKeys.indexOf(key);
if (index != -1){
storageKeys.remove(index);
storageValues.remove(index);
}
storageKeys.add(key);
storageValues.add(value);
this.rlpEncoded = null;
}
@ -145,7 +154,7 @@ public class NewContractDetails {
public Map<DataWord, DataWord> getStorage(){
Map<DataWord, DataWord> storage = Collections.unmodifiableMap(new HashMap<DataWord, DataWord>());
Map<DataWord, DataWord> storage = new HashMap<DataWord, DataWord>();
for (int i = 0;
storageKeys != null &&
@ -153,7 +162,7 @@ public class NewContractDetails {
storage.put(storageKeys.get(i), storageValues.get(i));
}
return storage;
return Collections.unmodifiableMap(storage);
}
}

View File

@ -1,7 +1,6 @@
package org.ethereum.db;
import org.ethereum.core.AccountState;
import org.ethereum.core.ContractDetails;
import org.ethereum.crypto.HashUtil;
import org.ethereum.trie.TrackTrie;
import org.ethereum.trie.Trie;
@ -98,7 +97,7 @@ public class Repository {
accountStateDB.update(addr, state.getEncoded());
// 2. Save ContractDetails
NewContractDetails details = new NewContractDetails();
ContractDetails details = new ContractDetails();
contractDetailsDB.put(addr, details.getEncoded());
return state;
@ -119,7 +118,7 @@ public class Repository {
return state;
}
public NewContractDetails getContractDetails(byte[] addr){
public ContractDetails getContractDetails(byte[] addr){
byte[] accountDetailsRLP = contractDetailsDB.get(addr);
@ -130,7 +129,7 @@ public class Repository {
return null;
}
NewContractDetails details = new NewContractDetails(accountDetailsRLP);
ContractDetails details = new ContractDetails(accountDetailsRLP);
return details;
}
@ -186,7 +185,7 @@ public class Repository {
if (address == null || key == null) return;
AccountState state = getAccountState(address);
NewContractDetails details = getContractDetails(address);
ContractDetails details = getContractDetails(address);
if (state == null || details == null) return;
details.put(key, value);
@ -211,7 +210,7 @@ public class Repository {
AccountState state = getAccountState(address);
if (state == null) return null;
NewContractDetails details = getContractDetails(address);
ContractDetails details = getContractDetails(address);
DataWord value = details.get(key);
return value;
@ -219,7 +218,7 @@ public class Repository {
public byte[] getCode(byte[] address){
NewContractDetails details = getContractDetails(address);
ContractDetails details = getContractDetails(address);
if (details == null) return null;
return details.getCode();
@ -232,7 +231,7 @@ public class Repository {
AccountState state = getAccountState(address);
if (state == null) return;
NewContractDetails details = getContractDetails(address);
ContractDetails details = getContractDetails(address);
details.setCode(code);
byte[] codeHash = HashUtil.sha3(code);

View File

@ -1,15 +1,13 @@
package org.ethereum.gui;
import org.ethereum.core.Account;
import org.ethereum.core.AccountState;
import org.ethereum.core.ContractDetails;
import org.ethereum.core.Transaction;
import org.ethereum.db.ContractDetails;
import org.ethereum.manager.MainData;
import org.ethereum.manager.WorldManager;
import org.ethereum.net.client.ClientPeer;
import org.ethereum.util.ByteUtil;
import org.ethereum.util.Utils;
import org.ethereum.vm.DataWord;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.spongycastle.util.BigIntegers;
@ -27,7 +25,6 @@ import java.awt.event.*;
import java.math.BigInteger;
import java.net.URL;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Pattern;
@ -229,35 +226,8 @@ class ContractCallDialog extends JDialog implements MessageAwareDialog{
}
byte[] contractAddress = Hex.decode( contractAddr );
byte[] contractStateB = WorldManager.instance.worldState.get(contractAddress);
if (contractStateB == null || contractStateB.length == 0){
return;
}
AccountState contractState = new AccountState(contractStateB);
final byte[] programCode = WorldManager.instance.chainDB.get(contractState.getCodeHash());
if (programCode == null || programCode.length == 0){
return;
}
byte[] contractDetailsB =
WorldManager.instance.detaildDB.get(contractAddress);
ContractDetails contractDetails = null;
final Map storageMap = new HashMap();
if (contractDetailsB != null){
contractDetails = new ContractDetails(contractDetailsB);
Map<DataWord, DataWord> tmpStorage = contractDetails.getStorage();
if (tmpStorage != null){
for (DataWord key : tmpStorage.keySet()){
String keyToSave = Hex.toHexString (key.getNoLeadZeroesData());
String valueToSave = Hex.toHexString (tmpStorage.get(key).getNoLeadZeroesData());
storageMap.put(keyToSave, valueToSave);
}
}
}
final byte[] programCode = WorldManager.instance.repository.getCode(contractAddress);
final Map storageMap = WorldManager.instance.repository.getContractDetails(contractAddress).getStorage();
contractDataInput.setBounds(70, 80, 350, 145);
contractDataInput.setViewportView(msgDataTA);
@ -335,31 +305,23 @@ class ContractCallDialog extends JDialog implements MessageAwareDialog{
private void playContractCall() {
byte[] contractAddress = Hex.decode( contractAddrInput.getText());
byte[] contractStateB = WorldManager.instance.worldState.get(contractAddress);
if (contractStateB == null || contractStateB.length == 0){
byte[] contractAddress = Hex.decode(contractAddrInput.getText());
ContractDetails contractDetails = WorldManager.instance.repository.getContractDetails(contractAddress);
if (contractDetails == null){
alertStatusMsg("No contract for that address");
return;
}
AccountState contractState = new AccountState(contractStateB);
byte[] programCode = WorldManager.instance.chainDB.get(contractState.getCodeHash());
byte[] programCode = WorldManager.instance.repository.getCode(contractAddress);
if (programCode == null || programCode.length == 0){
alertStatusMsg("Such account exist but no code in the db");
return;
}
byte[] contractDetailsB =
WorldManager.instance.detaildDB.get(contractAddress);
ContractDetails contractDetails = null;
if (contractDetailsB != null && contractDetailsB.length > 0)
contractDetails = new ContractDetails(contractDetailsB);
Transaction tx = createTransaction();
if (tx == null) return;
ProgramPlayDialog.createAndShowGUI(programCode, tx, WorldManager.instance.getBlockChain().getLastBlock(), contractDetails);
ProgramPlayDialog.createAndShowGUI(programCode, tx, WorldManager.instance.getBlockChain().getLastBlock());
}
protected JRootPane createRootPane() {

View File

@ -109,7 +109,7 @@ class ContractSubmitDialog extends JDialog implements MessageAwareDialog {
contractAddrInput.setText(Hex.toHexString(tx.getContractAddress()));
ProgramPlayDialog.createAndShowGUI(tx.getData(), tx,
WorldManager.instance.getBlockChain().getLastBlock(), null);
WorldManager.instance.getBlockChain().getLastBlock());
}}
);

View File

@ -1,14 +1,11 @@
package org.ethereum.gui;
import org.ethereum.core.Block;
import org.ethereum.core.ContractDetails;
import org.ethereum.core.Transaction;
import org.ethereum.db.TrackDatabase;
import org.ethereum.db.Repository;
import org.ethereum.manager.WorldManager;
import org.ethereum.serpent.SerpentCompiler;
import org.ethereum.trie.TrackTrie;
import org.ethereum.vm.*;
import org.spongycastle.util.encoders.Hex;
import javax.swing.*;
import javax.swing.event.ChangeEvent;
@ -16,7 +13,7 @@ import javax.swing.event.ChangeListener;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.*;
import java.util.ArrayList;
import java.util.List;
/**
@ -52,29 +49,23 @@ public class ProgramPlayDialog extends JPanel implements ActionListener,
}
public ProgramPlayDialog(byte[] code, Transaction tx, Block lastBlock, ContractDetails contractDetails) {
public ProgramPlayDialog(byte[] code, Transaction tx, Block lastBlock) {
this.tx = tx;
outputList = new ArrayList<String>();
VM vm = new VM();
TrackDatabase trackDetailDB = new TrackDatabase( WorldManager.instance.detaildDB );
TrackDatabase trackChainDb = new TrackDatabase( WorldManager.instance.chainDB);
TrackTrie trackStateDB = new TrackTrie(WorldManager.instance.worldState );
Repository tractRepository = WorldManager.instance.repository.getTrack();
Program program = new Program(code ,
ProgramInvokeFactory.createProgramInvoke(tx, lastBlock, contractDetails,
trackDetailDB, trackChainDb, trackStateDB));
ProgramInvokeFactory.createProgramInvoke(tx, lastBlock, tractRepository));
program.addListener(this);
program.fullTrace();
vm.play(program);
trackDetailDB.rollbackTrack();
trackChainDb.rollbackTrack();
trackStateDB.rollbackTrack();
tractRepository.rollback();
doGUI();
}
@ -155,11 +146,11 @@ public class ProgramPlayDialog extends JPanel implements ActionListener,
* this method should be invoked from the
* event-dispatching thread.
*/
public static void createAndShowGUI(byte[] runCode, Transaction tx, Block lastBlock, ContractDetails details) {
public static void createAndShowGUI(byte[] runCode, Transaction tx, Block lastBlock) {
ProgramPlayDialog ppd;
if (tx != null)
ppd = new ProgramPlayDialog(runCode, tx, lastBlock, details);
ppd = new ProgramPlayDialog(runCode, tx, lastBlock);
else{
ppd = new ProgramPlayDialog(runCode);
}
@ -204,7 +195,7 @@ public class ProgramPlayDialog extends JPanel implements ActionListener,
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI(code, null, null, null);
createAndShowGUI(code, null, null);
}
});

View File

@ -4,6 +4,7 @@ import org.ethereum.core.*;
import org.ethereum.crypto.ECKey;
import org.ethereum.crypto.HashUtil;
import org.ethereum.db.DatabaseImpl;
import org.ethereum.db.Repository;
import org.ethereum.db.TrackDatabase;
import org.ethereum.trie.TrackTrie;
import org.ethereum.trie.Trie;
@ -43,10 +44,8 @@ public class WorldManager {
Collections.synchronizedMap(new HashMap<String, Transaction>());
public DatabaseImpl chainDB = new DatabaseImpl("blockchain");
public DatabaseImpl stateDB = new DatabaseImpl("state");
public DatabaseImpl detaildDB = new DatabaseImpl("details");
public Trie worldState = new Trie(stateDB.getDb());
public Repository repository = new Repository();
public static WorldManager instance = new WorldManager();
public WorldManager() {
@ -84,19 +83,21 @@ public class WorldManager {
// 1. VALIDATE THE NONCE
byte[] senderAddress = tx.getSender();
byte[] stateData = worldState.get(senderAddress);
if (stateData == null || stateData.length == 0) {
AccountState senderAccount = repository.getAccountState(senderAddress);
if (senderAccount == null) {
if (stateLogger.isWarnEnabled())
stateLogger.warn("No such address: {}", Hex.toHexString(senderAddress));
return;
}
AccountState senderState = new AccountState(stateData);
if (senderState.getNonce().compareTo(new BigInteger(tx.getNonce())) != 0) {
BigInteger nonce = repository.getNonce(senderAddress);
if (nonce.compareTo(new BigInteger(tx.getNonce())) != 0) {
if (stateLogger.isWarnEnabled())
stateLogger.warn("Invalid nonce account.nonce={} tx.nonce={}",
senderState.getNonce(), new BigInteger(tx.getNonce()));
nonce.longValue(), new BigInteger(tx.getNonce()));
return;
}
@ -104,8 +105,9 @@ public class WorldManager {
// (THIS STAGE IS NOT REVERTED BY ANY EXCEPTION)
// first of all debit the gas from the issuer
AccountState receiverState = null;
BigInteger gasDebit = tx.getTotalGasValueDebit();
gasDebit = gasDebit.multiply(new BigInteger(tx.getGasPrice()));
byte[] contractAddress;
// Contract creation or existing Contract call
@ -113,32 +115,27 @@ public class WorldManager {
// credit the receiver
contractAddress = tx.getContractAddress();
receiverState = new AccountState();
worldState.update(contractAddress, receiverState.getEncoded());
repository.createAccount(contractAddress);
stateLogger.info("New contract created address={}",
Hex.toHexString(contractAddress));
} else {
contractAddress = tx.getReceiveAddress();
byte[] accountData = this.worldState.get(tx.getReceiveAddress());
if (accountData.length == 0){
receiverState = new AccountState();
AccountState receiverState = repository.getAccountState(tx.getReceiveAddress());
if (receiverState == null){
repository.createAccount(tx.getReceiveAddress());
if (stateLogger.isInfoEnabled())
stateLogger.info("New account created address={}",
Hex.toHexString(tx.getReceiveAddress()));
} else {
receiverState = new AccountState(accountData);
if (stateLogger.isInfoEnabled())
stateLogger.info("Account found address={}",
Hex.toHexString(tx.getReceiveAddress()));
}
}
// 2.2 UPDATE THE NONCE
// (THIS STAGE IS NOT REVERTED BY ANY EXCEPTION)
if (senderState.getBalance().compareTo(BigInteger.ZERO) == 1) {
senderState.incrementNonce();
worldState.update(tx.getSender(), senderState.getEncoded());
BigInteger balance = repository.getBalance(senderAddress);
if (balance.compareTo(BigInteger.ZERO) == 1) {
repository.increaseNonce(senderAddress);
if(stateLogger.isInfoEnabled())
stateLogger.info("Before contract execution the sender address debit with gas total cost, " +
@ -153,34 +150,30 @@ public class WorldManager {
// can be validate using GAS op
if (gasDebit.signum() == 1){
if (senderState.getBalance().subtract(gasDebit).signum() == -1){
if (balance.compareTo( gasDebit ) == -1){
logger.info("No gas to start the execution: sender={}" , Hex.toHexString(tx.getSender()));
return;
}
senderState.addToBalance(gasDebit.negate());
worldState.update(senderAddress, senderState.getEncoded());
repository.addBalance(senderAddress, gasDebit.negate());
}
// 3. START TRACKING FOR REVERT CHANGES OPTION !!!
TrackDatabase trackDetailDB = new TrackDatabase( WorldManager.instance.detaildDB );
TrackDatabase trackChainDb = new TrackDatabase( WorldManager.instance.chainDB);
TrackTrie trackStateDB = new TrackTrie(WorldManager.instance.worldState );
trackDetailDB.startTrack();
trackChainDb.startTrack();
trackStateDB.startTrack();
Repository trackRepository = repository.getTrack();
trackRepository.startTracking();
try {
// 4. THE SIMPLE VALUE/BALANCE CHANGE
if(tx.getValue() != null) {
if (senderState.getBalance().subtract(new BigInteger(1, tx.getValue())).signum() >= 0){
receiverState.addToBalance(new BigInteger(1, tx.getValue()));
senderState.addToBalance(new BigInteger(1, tx.getValue()).negate());
BigInteger senderBalance = repository.getBalance(senderAddress);
BigInteger contractBalance = repository.getBalance(contractAddress);
trackStateDB.update(senderAddress, senderState.getEncoded());
trackStateDB.update(contractAddress, receiverState.getEncoded());
if ( senderBalance.compareTo(new BigInteger(1, tx.getValue())) >= 0){
repository.addBalance(contractAddress, new BigInteger(1, tx.getValue()));
repository.addBalance(senderAddress, new BigInteger(1, tx.getValue()).negate());
if (stateLogger.isInfoEnabled())
stateLogger.info("Update value balance \n " +
@ -200,7 +193,7 @@ public class WorldManager {
blockChain.getLastBlock();
ProgramInvoke programInvoke =
ProgramInvokeFactory.createProgramInvoke(tx, lastBlock, null, trackDetailDB, trackChainDb, trackStateDB);
ProgramInvokeFactory.createProgramInvoke(tx, lastBlock, trackRepository);
if (logger.isInfoEnabled())
logger.info("running the init for contract: addres={}" ,
@ -211,14 +204,12 @@ public class WorldManager {
Program program = new Program(initCode, programInvoke);
vm.play(program);
ProgramResult result = program.getResult();
applyProgramResult(result, gasDebit, senderState, receiverState, senderAddress, tx.getContractAddress());
applyProgramResult(result, gasDebit, trackRepository, senderAddress, tx.getContractAddress());
} else {
if (receiverState.getCodeHash() != HashUtil.EMPTY_DATA_HASH){
byte[] programCode = chainDB.get(receiverState.getCodeHash());
if (programCode != null && programCode.length != 0){
byte[] programCode = trackRepository.getCode(tx.getReceiveAddress());
if (programCode != null){
Block lastBlock =
blockChain.getLastBlock();
@ -227,36 +218,24 @@ public class WorldManager {
logger.info("calling for existing contract: addres={}" , Hex.toHexString(tx.getReceiveAddress()));
// FETCH THE SAVED STORAGE
ContractDetails details = null;
byte[] detailsRLPData = detaildDB.get(tx.getReceiveAddress());
if (detailsRLPData.length > 0)
details = new ContractDetails(detailsRLPData);
ProgramInvoke programInvoke =
ProgramInvokeFactory.createProgramInvoke(tx, lastBlock, details, trackDetailDB, trackChainDb, trackStateDB);
ProgramInvokeFactory.createProgramInvoke(tx, lastBlock, trackRepository);
VM vm = new VM();
Program program = new Program(programCode, programInvoke);
vm.play(program);
ProgramResult result = program.getResult();
applyProgramResult(result, gasDebit, senderState, receiverState, senderAddress, tx.getReceiveAddress());
}
applyProgramResult(result, gasDebit, trackRepository, senderAddress, tx.getReceiveAddress());
}
}
} catch (RuntimeException e) {
trackDetailDB.rollbackTrack();
trackChainDb.rollbackTrack();
trackStateDB.rollbackTrack();
trackRepository.rollback();
return;
}
trackDetailDB.commitTrack();
trackChainDb.commitTrack();
trackStateDB.commitTrack();
trackRepository.commit();
pendingTransactions.put(Hex.toHexString(tx.getHash()), tx);
}
@ -268,13 +247,11 @@ public class WorldManager {
*
* @param result
* @param gasDebit
* @param senderState
* @param receiverState
* @param senderAddress
* @param contractAddress
*/
private void applyProgramResult(ProgramResult result, BigInteger gasDebit,
AccountState senderState, AccountState receiverState,
Repository repository,
byte[] senderAddress, byte[] contractAddress) {
if (result.getException() != null &&
@ -300,20 +277,17 @@ public class WorldManager {
if(stateLogger.isInfoEnabled())
stateLogger.info("After contract execution the sender address refunded with gas leftover , \n sender={} \n contract={} \n gas_refund= {}",
Hex.toHexString(senderAddress) ,Hex.toHexString(contractAddress), refund);
senderState.addToBalance(refund);
worldState.update(senderAddress, senderState.getEncoded());
repository.addBalance(senderAddress, refund);
}
if (bodyCode != null){
byte[] codeKey = HashUtil.sha3(bodyCode);
chainDB.put(codeKey, bodyCode);
receiverState.setCodeHash(codeKey);
worldState.update(contractAddress, receiverState.getEncoded());
repository.saveCode(contractAddress, bodyCode);
if (stateLogger.isInfoEnabled())
stateLogger.info("saving code of the contract to the db:\n contract={} sha3(code)={} code={}",
stateLogger.info("saving code of the contract to the db:\n contract={} code={}",
Hex.toHexString(contractAddress),
Hex.toHexString(codeKey),
Hex.toHexString(bodyCode));
}
@ -346,6 +320,6 @@ public class WorldManager {
public void close() {
chainDB.close();
stateDB.close();
repository.close();
}
}

View File

@ -1,12 +1,8 @@
package org.ethereum.vm;
import org.ethereum.core.AccountState;
import org.ethereum.core.ContractDetails;
import org.ethereum.crypto.HashUtil;
import org.ethereum.db.TrackDatabase;
import org.ethereum.manager.WorldManager;
import org.ethereum.trie.TrackTrie;
import org.ethereum.util.RLP;
import org.ethereum.db.ContractDetails;
import org.ethereum.db.Repository;
import org.ethereum.util.Utils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -14,7 +10,8 @@ import org.spongycastle.util.encoders.Hex;
import java.math.BigInteger;
import java.nio.ByteBuffer;
import java.util.*;
import java.util.Arrays;
import java.util.Stack;
/**
* www.ethereumJ.com
@ -28,8 +25,8 @@ public class Program {
ProgramListener listener;
Stack<DataWord> stack = new Stack<DataWord>();
Map<DataWord, DataWord> storage = new HashMap<DataWord, DataWord>();
ByteBuffer memory = null;
byte[] programAddress;
ProgramResult result = new ProgramResult();
@ -44,18 +41,14 @@ public class Program {
gasLogger = LoggerFactory.getLogger("gas - " + invokeData.hashCode());
result.setStateDb(invokeData.getStateDb());
result.setChainDb(invokeData.getChainDb());
result.setDetailDB(invokeData.getDetaildDB());
result.setRepository(invokeData.getRepository());
if (ops == null) throw new RuntimeException("program can not run with ops: null");
this.invokeData = invokeData;
this.ops = ops;
if (invokeData.getStorage() != null){
storage = invokeData.getStorage();
}
programAddress = invokeData.getOwnerAddress().getNoLeadZeroesData();
}
public byte getCurrentOp(){
@ -229,22 +222,12 @@ public class Program {
// 1. FETCH THE CODE FROM THE MEMORY
ByteBuffer programCode = memoryChunk(memStart, memSize);
TrackTrie stateDB = new TrackTrie( result.getStateDb() );
TrackDatabase chainDB = new TrackDatabase( result.getChainDb() );
TrackDatabase detailDB = new TrackDatabase( result.getDetailDB() );
detailDB.startTrack();
chainDB.startTrack();
stateDB.startTrack();
if (logger.isInfoEnabled())
logger.info("creating a new contract");
Repository trackRepository = result.getRepository().getTrack();
trackRepository.startTracking();
byte[] senderAddress = this.getOwnerAddress().getNoLeadZeroesData();
byte[] data = stateDB.get( senderAddress );
AccountState senderState = new AccountState(data);
if (logger.isInfoEnabled())
logger.info("creating a new contract inside contract run: [{}]", Hex.toHexString(senderAddress));
// 2.1 PERFORM THE GAS VALUE TX
// (THIS STAGE IS NOT REVERTED BY ANY EXCEPTION)
@ -259,19 +242,17 @@ public class Program {
}
// 2.2 CREATE THE CONTRACT ADDRESS
byte[] nonce = senderState.getNonce().toByteArray();
byte[] nonce = trackRepository.getNonce(senderAddress).toByteArray();
byte[] newAddress = HashUtil.calcNewAddr(this.getOwnerAddress().getNoLeadZeroesData(), nonce);
// 2.3 UPDATE THE NONCE
// (THIS STAGE IS NOT REVERTED BY ANY EXCEPTION)
senderState.incrementNonce();
trackRepository.increaseNonce(senderAddress);
// 3. COOK THE INVOKE AND EXECUTE
ProgramInvoke programInvoke =
ProgramInvokeFactory.createProgramInvoke(this, DataWord.ZERO, null,
DataWord.ZERO, gas, BigInteger.ZERO,
null,
detailDB, chainDB, stateDB);
ProgramInvokeFactory.createProgramInvoke(this, DataWord.ZERO, DataWord.ZERO,
gas, BigInteger.ZERO, null, trackRepository);
VM vm = new VM();
Program program = new Program(programCode.array(), programInvoke);
@ -282,31 +263,18 @@ public class Program {
result.getException() instanceof Program.OutOfGasException){
logger.info("contract run halted by OutOfGas: new contract init ={}" , Hex.toHexString(newAddress));
detailDB.rollbackTrack();
chainDB.rollbackTrack();
stateDB.rollbackTrack();
trackRepository.rollback();
stackPushZero();
return;
}
// 4. CREATE THE CONTRACT OUT OF RETURN
byte[] code = result.getHReturn().array();
byte[] keyCode = HashUtil.sha3(code);
trackRepository.saveCode(newAddress, code);
ContractDetails contractDetails = new ContractDetails(program.storage);
AccountState state = new AccountState();
state.setCodeHash(keyCode);
stateDB.update(newAddress, state.getEncoded());
chainDB.put(keyCode, code);
detailDB.put(newAddress, contractDetails.getEncoded());
// IN SUCCESS PUSH THE ADDRESS IN THE STACK
// IN SUCCESS PUSH THE ADDRESS INTO THE STACK
stackPush(new DataWord(newAddress));
detailDB.commitTrack();
chainDB.commitTrack();
stateDB.commitTrack();
trackRepository.commit();
}
/**
@ -327,26 +295,11 @@ public class Program {
ByteBuffer data = memoryChunk(inDataOffs, inDataSize);
// FETCH THE SAVED STORAGE
ContractDetails details = null;
byte[] toAddress = toAddressDW.getNoLeadZeroesData();
byte[] detailsRLPData = invokeData.getDetaildDB().get(toAddress);
if (detailsRLPData != null && detailsRLPData.length > 0)
details = new ContractDetails(detailsRLPData);
AccountState receiverState;
byte[] accountData = result.getStateDb().get(toAddress);
if (accountData == null || accountData.length == 0){
logger.info("no saved address in db to call: address={}" ,Hex.toHexString(toAddress));
return;
} else{
receiverState = new AccountState(accountData);
}
// FETCH THE CODE
byte[] programCode = result.getChainDb().get(receiverState.getCodeHash());
byte[] programCode = this.result.getRepository().getCode(toAddress);
if (programCode != null && programCode.length != 0){
if (logger.isInfoEnabled())
@ -354,14 +307,6 @@ public class Program {
Hex.toHexString(toAddress));
byte[] senderAddress = this.getOwnerAddress().getNoLeadZeroesData();
byte[] senderStateB = this.result.getStateDb().get(senderAddress);
if (senderStateB == null){
logger.info("This should not happen in any case, this inside contract run is is evidence for contract to exist: \n" +
"address={}", Hex.toHexString(senderAddress));
return;
}
AccountState senderState = new AccountState(senderStateB);
// 2.1 PERFORM THE GAS VALUE TX
// (THIS STAGE IS NOT REVERTED BY ANY EXCEPTION)
@ -376,29 +321,19 @@ public class Program {
// 2.2 UPDATE THE NONCE
// (THIS STAGE IS NOT REVERTED BY ANY EXCEPTION)
senderState.incrementNonce();
this.result.repository.increaseNonce(senderAddress);
TrackTrie stateDB = new TrackTrie( result.getStateDb() );
TrackDatabase chainDB = new TrackDatabase( result.getChainDb() );
TrackDatabase detailDB = new TrackDatabase( result.getDetailDB() );
detailDB.startTrack();
chainDB.startTrack();
stateDB.startTrack();
Repository trackRepository = result.getRepository().getTrack();
trackRepository.startTracking();
// todo: check if the endowment can really be done
receiverState.addToBalance(endowmentValue.value());
stateDB.update(toAddress, receiverState.getEncoded());
Map<DataWord, DataWord> storage = null;
if (details != null)
storage = details.getStorage();
trackRepository.addBalance(toAddress, endowmentValue.value());
ProgramInvoke programInvoke =
ProgramInvokeFactory.createProgramInvoke(this, toAddressDW, storage,
endowmentValue, gas, receiverState.getBalance(),
ProgramInvokeFactory.createProgramInvoke(this, toAddressDW,
endowmentValue, gas, result.getRepository().getBalance(toAddress),
data.array(),
detailDB, chainDB, stateDB);
trackRepository);
VM vm = new VM();
Program program = new Program(programCode, programInvoke);
@ -409,9 +344,7 @@ public class Program {
result.getException() instanceof Program.OutOfGasException){
logger.info("contract run halted by OutOfGas: contract={}" , Hex.toHexString(toAddress));
detailDB.rollbackTrack();
chainDB.rollbackTrack();
stateDB.rollbackTrack();
trackRepository.rollback();
stackPushZero();
return;
}
@ -434,9 +367,7 @@ public class Program {
// 4. THE FLAG OF SUCCESS IS ONE PUSHED INTO THE STACK
stackPushOne();
detailDB.commitTrack();
chainDB.commitTrack();
stateDB.commitTrack();
trackRepository.commit();
stackPush(new DataWord(1));
// the gas spent in any internal outcome
@ -444,13 +375,6 @@ public class Program {
spendGas(result.getGasUsed(), " 'Total for CALL run' ");
logger.info("The usage of the gas in external call updated", result.getGasUsed());
// update the storage , it could
// change by the call
byte[] contractDetailBytes =
result.getDetailDB().get(getOwnerAddress().getNoLeadZeroesData());
if (contractDetailBytes != null){
this.storage = new ContractDetails(contractDetailBytes).getStorage();
}
}
}
@ -473,12 +397,7 @@ public class Program {
public void storageSave(byte[] key, byte[] val){
DataWord keyWord = new DataWord(key);
DataWord valWord = new DataWord(val);
storage.put(keyWord, valWord);
if (storage != null){
ContractDetails contractDetails = new ContractDetails(storage);
result.getDetailDB().put(getOwnerAddress().getNoLeadZeroesData() , contractDetails.getEncoded());
}
result.repository.addStorageRow(this.programAddress, keyWord, valWord);
}
public DataWord getOwnerAddress(){
@ -536,7 +455,7 @@ public class Program {
}
public DataWord storageLoad(DataWord key){
return storage.get(key);
return result.repository.getStorageValue(this.programAddress, key);
}
public DataWord getPrevHash(){
@ -584,10 +503,12 @@ public class Program {
}
if (stackData.length() > 0) stackData.insert(0, "\n");
ContractDetails contractDetails = this.result.getRepository().getContractDetails(this.programAddress);
StringBuilder storageData = new StringBuilder();
for (DataWord key : storage.keySet()){
for (DataWord key : contractDetails.getStorage().keySet()){
storageData.append(" ").append(key).append(" -> ").append(storage.get(key)).append("\n");
storageData.append(" ").append(key).append(" -> ").
append(contractDetails.getStorage().get(key)).append("\n");
}
if (storageData.length() > 0) storageData.insert(0, "\n");

View File

@ -1,5 +1,6 @@
package org.ethereum.vm;
import org.ethereum.db.Repository;
import org.ethereum.db.TrackDatabase;
import org.ethereum.trie.TrackTrie;
@ -32,11 +33,7 @@ public interface ProgramInvoke {
public DataWord getDifficulty();
public DataWord getGaslimit();
public Map<DataWord, DataWord> getStorage();
public TrackDatabase getDetaildDB();
public TrackDatabase getChainDb();
public TrackTrie getStateDb();
public Repository getRepository();
public boolean byTransaction();

View File

@ -1,18 +1,13 @@
package org.ethereum.vm;
import org.ethereum.core.AccountState;
import org.ethereum.core.Block;
import org.ethereum.core.ContractDetails;
import org.ethereum.core.Transaction;
import org.ethereum.db.TrackDatabase;
import org.ethereum.manager.WorldManager;
import org.ethereum.trie.TrackTrie;
import org.ethereum.db.Repository;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.spongycastle.util.encoders.Hex;
import java.math.BigInteger;
import java.util.Map;
/**
* www.ethereumJ.com
@ -26,8 +21,7 @@ public class ProgramInvokeFactory {
private static Logger logger = LoggerFactory.getLogger("VM");
// Invocation by the wire tx
public static ProgramInvoke createProgramInvoke(Transaction tx, Block lastBlock, ContractDetails details,
TrackDatabase detaildDB, TrackDatabase chainDb, TrackTrie stateDB){
public static ProgramInvoke createProgramInvoke(Transaction tx, Block lastBlock, Repository repository){
// https://ethereum.etherpad.mozilla.org/26
@ -44,13 +38,7 @@ public class ProgramInvokeFactory {
byte[] caller = tx.getSender();
/*** BALANCE op ***/
byte[] addressStateData = stateDB.get(address);
byte[] balance = null;
if (addressStateData.length == 0)
balance = new byte[]{0};
else
balance = new AccountState(addressStateData).getBalance().toByteArray();
byte[] balance = repository.getBalance(address).toByteArray();
/*** GASPRICE op ***/
@ -87,14 +75,8 @@ public class ProgramInvokeFactory {
/*** GASLIMIT op ***/
long gaslimit = lastBlock.getGasLimit();
/*** Map of storage values ***/
Map<DataWord, DataWord> storage = null;
if (details != null)
storage = details.getStorage();
detaildDB.startTrack();
chainDb.startTrack();
stateDB.startTrack();
repository.startTracking();
if (logger.isInfoEnabled()){
logger.info("Program invocation: \n" +
@ -132,8 +114,8 @@ public class ProgramInvokeFactory {
ProgramInvoke programInvoke =
new ProgramInvokeImpl(address, origin, caller, balance, gasPrice, gas, callValue, data,
lastHash, coinbase, timestamp, number, difficulty, gaslimit, storage,
detaildDB, chainDb, stateDB);
lastHash, coinbase, timestamp, number, difficulty, gaslimit,
repository);
return programInvoke;
}
@ -143,10 +125,9 @@ public class ProgramInvokeFactory {
* This invocation created for contract call contract
*/
public static ProgramInvoke createProgramInvoke(Program program, DataWord toAddress,
Map<DataWord, DataWord> storageIn,
DataWord inValue, DataWord inGas,
BigInteger balanceInt, byte[] dataIn,
TrackDatabase detailDB, TrackDatabase chainDB, TrackTrie stateDB){
Repository repository){
DataWord address = toAddress;
@ -166,8 +147,6 @@ public class ProgramInvokeFactory {
DataWord difficulty = program.getDifficulty();
DataWord gasLimit = program.getGaslimit();
Map<DataWord, DataWord> storage = storageIn;
if (logger.isInfoEnabled()){
logger.info("Program invocation: \n" +
@ -204,7 +183,7 @@ public class ProgramInvokeFactory {
return new ProgramInvokeImpl(address, origin, caller, balance, gasPrice, gas, callValue,
data, lastHash, coinbase, timestamp, number, difficulty, gasLimit,
storage, detailDB, chainDB, stateDB);
repository);
}
}

View File

@ -1,5 +1,6 @@
package org.ethereum.vm;
import org.ethereum.db.Repository;
import org.ethereum.db.TrackDatabase;
import org.ethereum.trie.TrackTrie;
import org.ethereum.util.ByteUtil;
@ -36,16 +37,13 @@ public class ProgramInvokeImpl implements ProgramInvoke {
Map<DataWord, DataWord> storage;
TrackDatabase detaildDB;
TrackDatabase chainDb;
TrackTrie stateDb;
Repository repository;
private boolean byTransaction = true;
public ProgramInvokeImpl(DataWord address, DataWord origin, DataWord caller, DataWord balance,
DataWord gasPrice, DataWord gas, DataWord callValue, byte[] msgData,
DataWord lastHash, DataWord coinbase, DataWord timestamp, DataWord number, DataWord difficulty,
DataWord gaslimit, Map<DataWord, DataWord> storage,
TrackDatabase detaildDB, TrackDatabase chainDb, TrackTrie stateDB) {
DataWord gaslimit, Repository repository) {
// Transaction env
this.address = address;
@ -67,9 +65,7 @@ public class ProgramInvokeImpl implements ProgramInvoke {
this.storage = storage;
this.detaildDB = detaildDB;
this.chainDb = chainDb;
this.stateDb = stateDB;
this.repository = repository;
this.byTransaction = false;
}
@ -78,8 +74,8 @@ public class ProgramInvokeImpl implements ProgramInvoke {
public ProgramInvokeImpl(byte[] address, byte[] origin, byte[] caller, byte[] balance,
byte[] gasPrice, byte[] gas, byte[] callValue, byte[] msgData,
byte[] lastHash, byte[] coinbase, long timestamp, long number, byte[] difficulty,
long gaslimit, Map<DataWord, DataWord> storage,
TrackDatabase detaildDB, TrackDatabase chainDb, TrackTrie stateDB) {
long gaslimit,
Repository repository) {
// Transaction env
this.address = new DataWord(address);
@ -101,9 +97,7 @@ public class ProgramInvokeImpl implements ProgramInvoke {
this.storage = storage;
this.detaildDB = detaildDB;
this.chainDb = chainDb;
this.stateDb = stateDB;
this.repository = repository;
}
/* ADDRESS op */
@ -225,17 +219,8 @@ public class ProgramInvokeImpl implements ProgramInvoke {
/* Storage */
public Map<DataWord, DataWord> getStorage(){ return storage; }
public TrackDatabase getDetaildDB() {
return detaildDB;
}
public TrackDatabase getChainDb() {
return chainDb;
}
public TrackTrie getStateDb() {
return stateDb;
public Repository getRepository() {
return repository;
}
@Override
@ -255,9 +240,7 @@ public class ProgramInvokeImpl implements ProgramInvoke {
if (balance != null ? !balance.equals(that.balance) : that.balance != null) return false;
if (callValue != null ? !callValue.equals(that.callValue) : that.callValue != null) return false;
if (caller != null ? !caller.equals(that.caller) : that.caller != null) return false;
if (chainDb != null ? !chainDb.equals(that.chainDb) : that.chainDb != null) return false;
if (coinbase != null ? !coinbase.equals(that.coinbase) : that.coinbase != null) return false;
if (detaildDB != null ? !detaildDB.equals(that.detaildDB) : that.detaildDB != null) return false;
if (difficulty != null ? !difficulty.equals(that.difficulty) : that.difficulty != null) return false;
if (gas != null ? !gas.equals(that.gas) : that.gas != null) return false;
if (gasPrice != null ? !gasPrice.equals(that.gasPrice) : that.gasPrice != null) return false;
@ -266,7 +249,7 @@ public class ProgramInvokeImpl implements ProgramInvoke {
if (number != null ? !number.equals(that.number) : that.number != null) return false;
if (origin != null ? !origin.equals(that.origin) : that.origin != null) return false;
if (prevHash != null ? !prevHash.equals(that.prevHash) : that.prevHash != null) return false;
if (stateDb != null ? !stateDb.equals(that.stateDb) : that.stateDb != null) return false;
if (repository != null ? !repository.equals(that.repository) : that.repository != null) return false;
if (storage != null ? !storage.equals(that.storage) : that.storage != null) return false;
if (timestamp != null ? !timestamp.equals(that.timestamp) : that.timestamp != null) return false;
@ -290,9 +273,7 @@ public class ProgramInvokeImpl implements ProgramInvoke {
result = 31 * result + (difficulty != null ? difficulty.hashCode() : 0);
result = 31 * result + (gaslimit != null ? gaslimit.hashCode() : 0);
result = 31 * result + (storage != null ? storage.hashCode() : 0);
result = 31 * result + (detaildDB != null ? detaildDB.hashCode() : 0);
result = 31 * result + (chainDb != null ? chainDb.hashCode() : 0);
result = 31 * result + (stateDb != null ? stateDb.hashCode() : 0);
result = 31 * result + (repository!= null ? repository.hashCode() : 0);
result = 31 * result + (byTransaction ? 1 : 0);
return result;
}

View File

@ -1,15 +1,10 @@
package org.ethereum.vm;
import org.ethereum.core.ContractDetails;
import org.ethereum.crypto.ECKey;
import org.ethereum.crypto.HashUtil;
import org.ethereum.db.TrackDatabase;
import org.ethereum.manager.WorldManager;
import org.ethereum.trie.TrackTrie;
import org.ethereum.db.Repository;
import org.spongycastle.util.encoders.Hex;
import java.util.Map;
/**
* www.ethereumJ.com
* @author: Roman Mandeleil
@ -20,20 +15,18 @@ public class ProgramInvokeMockImpl implements ProgramInvoke {
byte[] msgData;
TrackTrie stateDB = null;
TrackDatabase chainDb = null;
TrackDatabase detaildDB = null;
ContractDetails details = null;
String ownerAddress;
Repository repository = null;
String ownerAddress = "cd2a3d9f938e13cd947ec05abc7fe734df8dd826";
public ProgramInvokeMockImpl(byte[] msgDataRaw){
this();
this.msgData = msgDataRaw;
}
public ProgramInvokeMockImpl() {
this.repository = new Repository();
this.repository.createAccount(Hex.decode(ownerAddress));
}
/* ADDRESS op */
@ -171,51 +164,21 @@ public class ProgramInvokeMockImpl implements ProgramInvoke {
return new DataWord(gasLimit);
}
public void setStateDB(TrackTrie stateDB) {
this.stateDB = stateDB;
}
public void setChainDb(TrackDatabase chainDb) {
this.chainDb = chainDb;
}
public void setDetaildDB(TrackDatabase detaildDB) {
this.detaildDB = detaildDB;
}
public void setDetails(ContractDetails details) {
this.details = details;
}
public void setOwnerAddress(String ownerAddress) {
this.ownerAddress = ownerAddress;
}
@Override
public Map<DataWord, DataWord> getStorage() {
if (details == null) return null;
return details.getStorage();
}
@Override
public TrackDatabase getDetaildDB() {
return detaildDB;
}
@Override
public TrackDatabase getChainDb() {
return chainDb;
}
@Override
public TrackTrie getStateDb() {
return stateDB;
}
@Override
public boolean byTransaction() {
return true;
}
@Override
public Repository getRepository() {
return this.repository;
}
public void setRepository(Repository repository) {
this.repository = repository;
}
}

View File

@ -1,5 +1,6 @@
package org.ethereum.vm;
import org.ethereum.db.Repository;
import org.ethereum.db.TrackDatabase;
import org.ethereum.trie.TrackTrie;
@ -18,9 +19,7 @@ public class ProgramResult {
private ByteBuffer hReturn = null;
private RuntimeException exception;
TrackDatabase detailDB;
TrackDatabase chainDb;
TrackTrie stateDb;
Repository repository = null;
public void spendGas(int gas){
gasUsed += gas;
@ -48,27 +47,11 @@ public class ProgramResult {
this.exception = exception;
}
public TrackDatabase getDetailDB() {
return detailDB;
public Repository getRepository() {
return repository;
}
public void setDetailDB(TrackDatabase detailDB) {
this.detailDB = detailDB;
}
public TrackDatabase getChainDb() {
return chainDb;
}
public void setChainDb(TrackDatabase chainDb) {
this.chainDb = chainDb;
}
public TrackTrie getStateDb() {
return stateDb;
}
public void setStateDb(TrackTrie stateDb) {
this.stateDb = stateDb;
public void setRepository(Repository repository) {
this.repository = repository;
}
}

View File

@ -1,90 +0,0 @@
package org.ethereum.core;
import org.ethereum.vm.DataWord;
import org.junit.Assert;
import org.junit.Test;
import org.spongycastle.util.encoders.Hex;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
/**
* www.ethereumJ.com
*
* @author: Roman Mandeleil
* Created on: 09/06/2014 15:41
*/
public class ContractDetailsTest {
@Test /* encode 2 keys/values */
public void test1(){
String expected = "f888f842a00000000000000000000000000000000000000000000000000000000000000002a00000000000000000000000000000000000000000000000000000000000000001f842a00000000000000000000000000000000000000000000000000000000000009dd4a0000000000000000000000000000000000000000000000000000000000000765f";
DataWord key1 = new DataWord(1);
DataWord value1 = new DataWord(30303);
DataWord key2 = new DataWord(2);
DataWord value2 = new DataWord(40404);
HashMap<DataWord, DataWord> storage = new HashMap<>();
storage.put(key1, value1);
storage.put(key2, value2);
ContractDetails contractDetails = new ContractDetails(storage);
String encoded = Hex.toHexString(contractDetails.getEncoded());
Assert.assertEquals(expected, encoded);
}
@Test /* encode 3 keys/values */
public void test2(){
String expected = "f8caf863a00000000000000000000000000000000000000000000000000000000000000002a00000000000000000000000000000000000000000000000000000000000000001a00000000000000000000000000000000000000000000000000000000000000003f863a00000000000000000000000000000000000000000000000000000000000009dd4a0000000000000000000000000000000000000000000000000000000000000765fa0000000000000000000000000000000000000000000000000000000000000ffff";
DataWord key1 = new DataWord(1);
DataWord value1 = new DataWord(30303);
DataWord key2 = new DataWord(2);
DataWord value2 = new DataWord(40404);
DataWord key3 = new DataWord(3);
DataWord value3 = new DataWord(0xFFFF);
HashMap<DataWord, DataWord> storage = new HashMap<>();
storage.put(key1, value1);
storage.put(key2, value2);
storage.put(key3, value3);
ContractDetails contractDetails = new ContractDetails(storage);
String encoded = Hex.toHexString(contractDetails.getEncoded());
Assert.assertEquals(expected, encoded);
}
@Test /* decode 3 keys/values */
public void test3(){
String rlpData = "f8caf863a00000000000000000000000000000000000000000000000000000000000000002a00000000000000000000000000000000000000000000000000000000000000001a00000000000000000000000000000000000000000000000000000000000000003f863a00000000000000000000000000000000000000000000000000000000000009dd4a0000000000000000000000000000000000000000000000000000000000000765fa0000000000000000000000000000000000000000000000000000000000000ffff";
ContractDetails contractDetails = new ContractDetails(Hex.decode(rlpData));
String expKey3String = "0000000000000000000000000000000000000000000000000000000000000003";
String expVal3String = "000000000000000000000000000000000000000000000000000000000000ffff";
DataWord key3 = contractDetails.storageKeys.get(2);
DataWord value3 = contractDetails.storageValues.get(2);
String key3String = Hex.toHexString(key3.getData());
String value3String = Hex.toHexString(value3.getData());
Assert.assertEquals(expKey3String, key3String);
Assert.assertEquals(expVal3String, value3String);
}
}

View File

@ -1,7 +1,6 @@
package org.ethereum.db;
import org.ethereum.core.AccountState;
import org.ethereum.core.ContractDetails;
import org.ethereum.vm.DataWord;
import org.junit.*;
import org.junit.runners.MethodSorters;

View File

@ -1,17 +1,14 @@
package org.ethereum.vm;
import org.abego.treelayout.internal.util.Contract;
import org.ethereum.core.AccountState;
import org.ethereum.core.ContractDetails;
import org.ethereum.crypto.HashUtil;
import org.ethereum.db.TrackDatabase;
import org.ethereum.manager.WorldManager;
import org.ethereum.trie.TrackTrie;
import org.ethereum.db.Repository;
import org.junit.FixMethodOrder;
import org.junit.Test;
import org.junit.runners.MethodSorters;
import org.spongycastle.util.encoders.Hex;
import java.math.BigInteger;
import java.util.HashMap;
import static org.junit.Assert.assertEquals;
@ -22,6 +19,7 @@ import static org.junit.Assert.assertEquals;
* Created on: 16/06/2014 10:37
*/
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class VMComplexTest {
@ -47,12 +45,6 @@ public class VMComplexTest {
DataWord key1 = new DataWord(999);
DataWord value1 = new DataWord(3);
HashMap<DataWord, DataWord> storage = new HashMap<>();
storage.put(key1, value1);
ContractDetails contractDetails = new ContractDetails(storage);
// Set contract into Database
String callerAddr = "cd2a3d9f938e13cd947ec05abc7fe734df8dd826";
String contractAddr = "77045e71a7a2c50903d88e564cd72fab11e82051";
@ -66,24 +58,18 @@ public class VMComplexTest {
AccountState accountState = new AccountState();
accountState.setCodeHash(codeKey);
AccountState callerAcountState = new AccountState();
callerAcountState.addToBalance(new BigInteger("100000000000000000000"));
WorldManager.instance.worldState.update(callerAddrB, callerAcountState.getEncoded());
WorldManager.instance.worldState.update(contractAddrB, accountState.getEncoded());
WorldManager.instance.chainDB.put(codeKey, codeB);
WorldManager.instance.detaildDB.put(contractAddrB, contractDetails.getEncoded());
TrackTrie stateDB = new TrackTrie(WorldManager.instance.worldState);
TrackDatabase chainDb = new TrackDatabase(WorldManager.instance.chainDB);
TrackDatabase detaildDB = new TrackDatabase(WorldManager.instance.detaildDB);
ProgramInvokeMockImpl pi = new ProgramInvokeMockImpl();
pi.setDetaildDB(detaildDB);
pi.setChainDb(chainDb);
pi.setStateDB(stateDB);
pi.setDetails(contractDetails);
pi.setOwnerAddress("77045e71a7a2c50903d88e564cd72fab11e82051");
Repository repository = pi.getRepository();
repository.createAccount(callerAddrB);
repository.addBalance(callerAddrB, new BigInteger("100000000000000000000"));
repository.createAccount(contractAddrB);
repository.saveCode(contractAddrB, codeB);
repository.addStorageRow(contractAddrB, key1, value1);
// Play the program
@ -100,15 +86,15 @@ public class VMComplexTest {
System.out.println();
System.out.println("============ Results ============");
AccountState as =
new AccountState(WorldManager.instance.worldState.get(
Hex.decode( contractAddr) ));
BigInteger balance = repository.getBalance(callerAddrB);
System.out.println("*** Used gas: " + program.result.getGasUsed());
System.out.println("*** Contract Balance: " + as.getBalance());
System.out.println("*** Contract Balance: " + balance);
// todo: assert caller balance after contract exec
repository.close();
assertEquals(expectedGas, program.result.getGasUsed());
}
@ -153,34 +139,23 @@ public class VMComplexTest {
byte[] contractA_addr_bytes = Hex.decode(contractA_addr);
byte[] codeA = Hex.decode(code_a);
byte[] codeA_Key = HashUtil.sha3(codeA);
AccountState accountState_a = new AccountState();
accountState_a.setCodeHash(codeA_Key);
WorldManager.instance.worldState.update(contractA_addr_bytes, accountState_a.getEncoded());
ProgramInvokeMockImpl pi = new ProgramInvokeMockImpl();
pi.setOwnerAddress(contractB_addr);
Repository repository = pi.repository;
byte[] contractB_addr_bytes = Hex.decode(contractB_addr);
byte[] codeB = Hex.decode(code_b);
byte[] codeB_Key = HashUtil.sha3(codeB);
AccountState accountState_b = new AccountState();
accountState_b.setCodeHash(codeB_Key);
WorldManager.instance.worldState.update(contractB_addr_bytes, accountState_a.getEncoded());
AccountState callerAcountState = new AccountState();
callerAcountState.addToBalance(new BigInteger("100000000000000000000"));
WorldManager.instance.worldState.update(caller_addr_bytes, callerAcountState.getEncoded());
repository.createAccount(contractA_addr_bytes);
repository.saveCode(contractA_addr_bytes, codeA);
WorldManager.instance.chainDB.put(codeA_Key, codeA);
repository.createAccount(contractB_addr_bytes);
repository.saveCode(contractB_addr_bytes, codeB);
TrackTrie stateDB = new TrackTrie(WorldManager.instance.worldState);
TrackDatabase chainDb = new TrackDatabase(WorldManager.instance.chainDB);
TrackDatabase detaildDB = new TrackDatabase(WorldManager.instance.detaildDB);
repository.createAccount(caller_addr_bytes);
repository.addBalance(caller_addr_bytes, new BigInteger("100000000000000000000"));
ProgramInvokeMockImpl pi = new ProgramInvokeMockImpl();
pi.setDetaildDB(detaildDB);
pi.setChainDb(chainDb);
pi.setStateDB(stateDB);
pi.setDetails(null);
pi.setOwnerAddress(contractB_addr);
// ****************** //
// Play the program //
@ -198,27 +173,20 @@ public class VMComplexTest {
System.out.println();
System.out.println("============ Results ============");
AccountState as =
new AccountState(WorldManager.instance.worldState.get(
Hex.decode( contractA_addr) ));
System.out.println("*** Used gas: " + program.result.getGasUsed());
byte[] rlpBytes = WorldManager.instance.detaildDB.get(contractA_addr_bytes);
ContractDetails details = new ContractDetails(rlpBytes);
DataWord value_1 = details.getStorage().get(new DataWord(00));
DataWord value_2 = details.getStorage().get(new DataWord(01));
DataWord value_1 = repository.getStorageValue(contractA_addr_bytes, new DataWord(00));
DataWord value_2 = repository.getStorageValue(contractA_addr_bytes, new DataWord(01));
repository.close();
assertEquals(expectedVal_1, value_1.longValue());
assertEquals(expectedVal_2, value_2.longValue());
// todo: check that the value pushed after exec is 1
}
@ -270,34 +238,22 @@ public class VMComplexTest {
byte[] contractA_addr_bytes = Hex.decode(contractA_addr);
byte[] codeA = Hex.decode(code_a);
byte[] codeA_Key = HashUtil.sha3(codeA);
AccountState accountState_a = new AccountState();
accountState_a.setCodeHash(codeA_Key);
WorldManager.instance.worldState.update(contractA_addr_bytes, accountState_a.getEncoded());
byte[] contractB_addr_bytes = Hex.decode(contractB_addr);
byte[] codeB = Hex.decode(code_b);
byte[] codeB_Key = HashUtil.sha3(codeB);
AccountState accountState_b = new AccountState();
accountState_b.setCodeHash(codeB_Key);
WorldManager.instance.worldState.update(contractB_addr_bytes, accountState_a.getEncoded());
AccountState callerAcountState = new AccountState();
callerAcountState.addToBalance(new BigInteger("100000000000000000000"));
WorldManager.instance.worldState.update(caller_addr_bytes, callerAcountState.getEncoded());
WorldManager.instance.chainDB.put(codeA_Key, codeA);
TrackTrie stateDB = new TrackTrie(WorldManager.instance.worldState);
TrackDatabase chainDb = new TrackDatabase(WorldManager.instance.chainDB);
TrackDatabase detaildDB = new TrackDatabase(WorldManager.instance.detaildDB);
ProgramInvokeMockImpl pi = new ProgramInvokeMockImpl();
pi.setDetaildDB(detaildDB);
pi.setChainDb(chainDb);
pi.setStateDB(stateDB);
pi.setDetails(null);
pi.setOwnerAddress(contractB_addr);
Repository repository = pi.getRepository();
repository.createAccount(contractA_addr_bytes);
repository.saveCode(contractA_addr_bytes, codeA);
repository.createAccount(contractB_addr_bytes);
repository.saveCode(contractB_addr_bytes, codeB);
repository.createAccount(caller_addr_bytes);
repository.addBalance(caller_addr_bytes, new BigInteger("100000000000000000000"));
// ****************** //
// Play the program //
@ -312,12 +268,8 @@ public class VMComplexTest {
program.setRuntimeFailure(e);
}
System.out.println();
System.out.println("============ Results ============");
AccountState as =
new AccountState(WorldManager.instance.worldState.get(
Hex.decode( contractA_addr) ));
System.out.println("*** Used gas: " + program.result.getGasUsed());
@ -329,6 +281,8 @@ public class VMComplexTest {
DataWord value5 = program.memoryLoad(new DataWord(160));
DataWord value6 = program.memoryLoad(new DataWord(192));
repository.close();
assertEquals(expectedVal_1, value1.longValue());
assertEquals(expectedVal_2, value2.longValue());
assertEquals(expectedVal_3, value3.longValue());
@ -337,7 +291,6 @@ public class VMComplexTest {
assertEquals(expectedVal_6, value6.longValue());
// todo: check that the value pushed after exec is 1
}
@ -374,31 +327,20 @@ public class VMComplexTest {
"005460206000f2000000000000000000000000" +
"0000000000000000000000602054602960006064f0";
ProgramInvokeMockImpl pi = new ProgramInvokeMockImpl();
pi.setOwnerAddress(contractA_addr);
Repository repository = pi.repository;
byte[] caller_addr_bytes = Hex.decode(callerAddr);
byte[] contractA_addr_bytes = Hex.decode(contractA_addr);
byte[] codeA = Hex.decode(code_a);
byte[] codeA_Key = HashUtil.sha3(codeA);
AccountState accountState_a = new AccountState();
accountState_a.setCodeHash(codeA_Key);
WorldManager.instance.worldState.update(contractA_addr_bytes, accountState_a.getEncoded());
AccountState callerAcountState = new AccountState();
callerAcountState.addToBalance(new BigInteger("100000000000000000000"));
WorldManager.instance.worldState.update(caller_addr_bytes, callerAcountState.getEncoded());
repository.createAccount(contractA_addr_bytes);
repository.saveCode(contractA_addr_bytes, codeA);
WorldManager.instance.chainDB.put(codeA_Key, codeA);
TrackTrie stateDB = new TrackTrie(WorldManager.instance.worldState);
TrackDatabase chainDb = new TrackDatabase(WorldManager.instance.chainDB);
TrackDatabase detaildDB = new TrackDatabase(WorldManager.instance.detaildDB);
ProgramInvokeMockImpl pi = new ProgramInvokeMockImpl();
pi.setDetaildDB(detaildDB);
pi.setChainDb(chainDb);
pi.setStateDB(stateDB);
pi.setDetails(null);
pi.setOwnerAddress(contractA_addr);
repository.createAccount(caller_addr_bytes);
// ****************** //
// Play the program //
@ -416,16 +358,11 @@ public class VMComplexTest {
System.out.println();
System.out.println("============ Results ============");
AccountState as =
new AccountState(WorldManager.instance.worldState.get(
Hex.decode( contractA_addr) ));
System.out.println("*** Used gas: " + program.result.getGasUsed());
// todo: check that the value pushed after exec is the new address
repository.close();
}

File diff suppressed because it is too large Load Diff