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, difficulty, number, minGasPrice, gasLimit, gasUsed,
timestamp, extraData, nonce); timestamp, extraData, nonce);
this.txsState = new Trie(null); 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.header.setTxTrieRoot(txsState.getRootHash());
this.transactionsList = transactionsList; this.transactionsList = transactionsList;
this.uncleList = uncleList; this.uncleList = uncleList;
@ -197,7 +201,7 @@ public class Block {
public List<Transaction> getTransactionsList() { public List<Transaction> getTransactionsList() {
if (!parsed) parseRLP(); if (!parsed) parseRLP();
if (transactionsList == null) { if (transactionsList == null) {
this.transactionsList = new ArrayList<Transaction>(); this.transactionsList = new ArrayList<>();
} }
return transactionsList; return transactionsList;
} }
@ -205,7 +209,7 @@ public class Block {
public List<TransactionReceipt> getTxReceiptList() { public List<TransactionReceipt> getTxReceiptList() {
if (!parsed) parseRLP(); if (!parsed) parseRLP();
if (transactionsList == null) { if (transactionsList == null) {
this.txReceiptList = new ArrayList<TransactionReceipt>(); this.txReceiptList = new ArrayList<>();
} }
return txReceiptList; return txReceiptList;
} }
@ -213,7 +217,7 @@ public class Block {
public List<Block> getUncleList() { public List<Block> getUncleList() {
if (!parsed) parseRLP(); if (!parsed) parseRLP();
if (uncleList == null) { if (uncleList == null) {
this.uncleList = new ArrayList<Block>(); this.uncleList = new ArrayList<>();
} }
return uncleList; return uncleList;
} }
@ -299,14 +303,6 @@ public class Block {
// this.allAccountsState.update(); // 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; * 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 * a smaller period between the last two blocks results in an increase in the
@ -320,7 +316,6 @@ public class Block {
if(!this.isGenesis()) { if(!this.isGenesis()) {
// verify difficulty meets requirements // verify difficulty meets requirements
isValid = this.getDifficulty() == this.calcDifficulty(); isValid = this.getDifficulty() == this.calcDifficulty();
// verify nonce meest difficulty requirements
isValid = this.validateNonce(); isValid = this.validateNonce();
// verify gasLimit meets requirements // verify gasLimit meets requirements
isValid = this.getGasLimit() == this.calcGasLimit(); isValid = this.getGasLimit() == this.calcGasLimit();
@ -367,9 +362,6 @@ public class Block {
/** /**
* Verify that block is valid for its difficulty * Verify that block is valid for its difficulty
* *
* @param block
* @param difficulty
* @param testNonce
* @return * @return
*/ */
public boolean validateNonce() { 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 java.math.BigInteger;
import org.ethereum.crypto.HashUtil; import org.ethereum.crypto.HashUtil;
import org.ethereum.manager.WorldManager;
import org.ethereum.util.RLP; import org.ethereum.util.RLP;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -69,7 +70,8 @@ public class Genesis extends Block {
// Premine state // Premine state
for (String address : premine) { 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-hash: " + Hex.toHexString(this.getHash()));
logger.info("Genesis-stateRoot: " + Hex.toHexString(this.getStateRoot())); logger.info("Genesis-stateRoot: " + Hex.toHexString(this.getStateRoot()));

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,15 +1,10 @@
package org.ethereum.vm; package org.ethereum.vm;
import org.ethereum.core.ContractDetails;
import org.ethereum.crypto.ECKey; import org.ethereum.crypto.ECKey;
import org.ethereum.crypto.HashUtil; import org.ethereum.crypto.HashUtil;
import org.ethereum.db.TrackDatabase; import org.ethereum.db.Repository;
import org.ethereum.manager.WorldManager;
import org.ethereum.trie.TrackTrie;
import org.spongycastle.util.encoders.Hex; import org.spongycastle.util.encoders.Hex;
import java.util.Map;
/** /**
* www.ethereumJ.com * www.ethereumJ.com
* @author: Roman Mandeleil * @author: Roman Mandeleil
@ -20,20 +15,18 @@ public class ProgramInvokeMockImpl implements ProgramInvoke {
byte[] msgData; byte[] msgData;
TrackTrie stateDB = null; Repository repository = null;
TrackDatabase chainDb = null; String ownerAddress = "cd2a3d9f938e13cd947ec05abc7fe734df8dd826";
TrackDatabase detaildDB = null;
ContractDetails details = null;
String ownerAddress;
public ProgramInvokeMockImpl(byte[] msgDataRaw){ public ProgramInvokeMockImpl(byte[] msgDataRaw){
this();
this.msgData = msgDataRaw; this.msgData = msgDataRaw;
} }
public ProgramInvokeMockImpl() { public ProgramInvokeMockImpl() {
this.repository = new Repository();
this.repository.createAccount(Hex.decode(ownerAddress));
} }
/* ADDRESS op */ /* ADDRESS op */
@ -171,51 +164,21 @@ public class ProgramInvokeMockImpl implements ProgramInvoke {
return new DataWord(gasLimit); 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) { public void setOwnerAddress(String ownerAddress) {
this.ownerAddress = 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 @Override
public boolean byTransaction() { public boolean byTransaction() {
return true; 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; package org.ethereum.vm;
import org.ethereum.db.Repository;
import org.ethereum.db.TrackDatabase; import org.ethereum.db.TrackDatabase;
import org.ethereum.trie.TrackTrie; import org.ethereum.trie.TrackTrie;
@ -18,9 +19,7 @@ public class ProgramResult {
private ByteBuffer hReturn = null; private ByteBuffer hReturn = null;
private RuntimeException exception; private RuntimeException exception;
TrackDatabase detailDB; Repository repository = null;
TrackDatabase chainDb;
TrackTrie stateDb;
public void spendGas(int gas){ public void spendGas(int gas){
gasUsed += gas; gasUsed += gas;
@ -48,27 +47,11 @@ public class ProgramResult {
this.exception = exception; this.exception = exception;
} }
public TrackDatabase getDetailDB() { public Repository getRepository() {
return detailDB; return repository;
} }
public void setDetailDB(TrackDatabase detailDB) { public void setRepository(Repository repository) {
this.detailDB = detailDB; this.repository = repository;
}
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;
} }
} }

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; package org.ethereum.db;
import org.ethereum.core.AccountState; import org.ethereum.core.AccountState;
import org.ethereum.core.ContractDetails;
import org.ethereum.vm.DataWord; import org.ethereum.vm.DataWord;
import org.junit.*; import org.junit.*;
import org.junit.runners.MethodSorters; import org.junit.runners.MethodSorters;

View File

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

File diff suppressed because it is too large Load Diff