mirror of
https://github.com/status-im/ethereumj-personal.git
synced 2025-02-06 09:03:31 +00:00
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:
parent
9d650350f0
commit
415f87c727
@ -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() {
|
||||||
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
@ -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,8 +70,9 @@ 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()));
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -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);
|
||||||
|
@ -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() {
|
||||||
|
@ -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());
|
||||||
}}
|
}}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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");
|
||||||
|
|
||||||
|
@ -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();
|
||||||
|
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
@ -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;
|
||||||
|
@ -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
Loading…
x
Reference in New Issue
Block a user