Fixing consensus bugs:
+ clone for invoke data (if not changed unsafe changes will corrupt the env) + tx got into sign byte problem + significant improve over VM short tracing
This commit is contained in:
parent
f7d2c80eba
commit
2be0364145
|
@ -31,6 +31,7 @@ public class SystemProperties {
|
|||
private static Boolean DEFAULT_DUMP_FULL = false;
|
||||
private static String DEFAULT_DUMP_DIR = "dmp";
|
||||
private static Boolean DEFAULT_DUMP_CLEAN_ON_RESTART = true;
|
||||
private static int DEFAULT_TRACE_STARTBLOCK = -1;
|
||||
|
||||
public static SystemProperties CONFIG = new SystemProperties();
|
||||
private Properties prop = new Properties();
|
||||
|
@ -132,6 +133,12 @@ public class SystemProperties {
|
|||
return Integer.parseInt(prop.getProperty("active.peer.channel.timeout"));
|
||||
}
|
||||
|
||||
public Integer traceStartBlock() {
|
||||
if(prop.isEmpty()) return DEFAULT_TRACE_STARTBLOCK;
|
||||
return Integer.parseInt(prop.getProperty("trace.startblock"));
|
||||
}
|
||||
|
||||
|
||||
public Boolean dumpFull() {
|
||||
if(prop.isEmpty()) return DEFAULT_DUMP_FULL;
|
||||
return Boolean.parseBoolean(prop.getProperty("dump.full"));
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
package org.ethereum.core;
|
||||
|
||||
import static org.ethereum.config.SystemProperties.CONFIG;
|
||||
import org.apache.log4j.PropertyConfigurator;
|
||||
import org.ethereum.db.DatabaseImpl;
|
||||
import org.ethereum.manager.WorldManager;
|
||||
import org.ethereum.util.ByteUtil;
|
||||
|
@ -9,9 +11,13 @@ import org.slf4j.LoggerFactory;
|
|||
import org.spongycastle.util.encoders.Hex;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
import java.net.URL;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.ethereum.core.Denomination.*;
|
||||
import static org.ethereum.core.Denomination.SZABO;
|
||||
|
||||
/**
|
||||
* The Ethereum blockchain is in many ways similar to the Bitcoin blockchain,
|
||||
|
@ -103,16 +109,28 @@ public class Blockchain {
|
|||
for (int i = blocks.size() - 1; i >= 0 ; --i) {
|
||||
this.addBlock(blocks.get(i));
|
||||
|
||||
// here we can turn on the detail tracing in the middle of the chain
|
||||
if (lastBlock.getNumber() >= CONFIG.traceStartBlock() && CONFIG.traceStartBlock() != -1) {
|
||||
|
||||
URL configFile = ClassLoader
|
||||
.getSystemResource("log4j-detailed.properties");
|
||||
|
||||
PropertyConfigurator.configure(configFile);
|
||||
}
|
||||
|
||||
long blockNum = blocks.get(i).getNumber();
|
||||
/* Debug check to see if the state is still as expected */
|
||||
if(logger.isWarnEnabled()) {
|
||||
String blockStateRootHash = Hex.toHexString(blocks.get(i).getStateRoot());
|
||||
String worldStateRootHash = Hex.toHexString(WorldManager.getInstance().getRepository().getWorldState().getRootHash());
|
||||
if(!blockStateRootHash.equals(worldStateRootHash))
|
||||
logger.warn("WARNING: STATE CONFLICT! block: {} worldstate {} mismatch", blockNum, worldStateRootHash);
|
||||
}
|
||||
if(!blockStateRootHash.equals(worldStateRootHash)){
|
||||
logger.warn("WARNING: STATE CONFLICT! block: {} worldstate {} mismatch", blockNum, worldStateRootHash);
|
||||
|
||||
System.exit(-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Remove all wallet transactions as they already approved by the net
|
||||
for (Block block : blocks) {
|
||||
for (Transaction tx : block.getTransactionsList()) {
|
||||
|
@ -122,6 +140,16 @@ public class Blockchain {
|
|||
}
|
||||
}
|
||||
logger.info("*** Block chain size: [ {} ]", this.getSize());
|
||||
|
||||
/*
|
||||
if (lastBlock.getNumber() >= 30) {
|
||||
System.out.println("** checkpoint **");
|
||||
|
||||
this.close();
|
||||
WorldManager.getInstance().getRepository().close();
|
||||
System.exit(1);
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
public void addBlock(Block block) {
|
||||
|
|
|
@ -45,32 +45,24 @@ public class ContractDetails {
|
|||
if (value.equals(DataWord.ZERO)){
|
||||
|
||||
storageTrie.delete(key.getData());
|
||||
|
||||
int index = storageKeys.indexOf(key);
|
||||
if (index != -1) {
|
||||
storageKeys.remove(index);
|
||||
storageValues.remove(index);
|
||||
}
|
||||
|
||||
this.rlpEncoded = null;
|
||||
|
||||
|
||||
} else{
|
||||
|
||||
storageTrie.update(key.getData(), RLP.encodeElement( value.getNoLeadZeroesData() ));
|
||||
|
||||
int index = storageKeys.indexOf(key);
|
||||
|
||||
if (index != -1) {
|
||||
storageKeys.remove(index);
|
||||
storageValues.remove(index);
|
||||
}
|
||||
|
||||
storageKeys.add(key);
|
||||
storageValues.add(value);
|
||||
|
||||
this.rlpEncoded = null;
|
||||
}
|
||||
|
||||
this.rlpEncoded = null;
|
||||
}
|
||||
|
||||
public DataWord get(DataWord key) {
|
||||
|
@ -101,6 +93,8 @@ public class ContractDetails {
|
|||
}
|
||||
|
||||
public byte[] getStorageHash() {
|
||||
|
||||
getEncoded();
|
||||
return storageTrie.getRootHash();
|
||||
}
|
||||
|
||||
|
@ -154,6 +148,13 @@ public class ContractDetails {
|
|||
DataWord value = storageValues.get(i);
|
||||
values[i] = RLP.encodeElement(value.getNoLeadZeroesData());
|
||||
}
|
||||
|
||||
storageTrie = new Trie(null);
|
||||
// calc the trie for root hash
|
||||
for (int i = 0; i < storageKeys.size(); ++i){
|
||||
storageTrie.update(storageKeys.get(i).getData(), values[i]);
|
||||
}
|
||||
|
||||
byte[] rlpKeysList = RLP.encodeList(keys);
|
||||
byte[] rlpValuesList = RLP.encodeList(values);
|
||||
byte[] rlpCode = RLP.encodeElement(code);
|
||||
|
|
|
@ -4,12 +4,14 @@ import org.codehaus.plexus.util.FileUtils;
|
|||
import org.ethereum.core.AccountState;
|
||||
import org.ethereum.crypto.HashUtil;
|
||||
import org.ethereum.json.JSONHelper;
|
||||
import org.ethereum.manager.WorldManager;
|
||||
import org.ethereum.trie.TrackTrie;
|
||||
import org.ethereum.trie.Trie;
|
||||
import org.ethereum.util.ByteUtil;
|
||||
import org.ethereum.vm.DataWord;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.spongycastle.util.BigIntegers;
|
||||
import org.spongycastle.util.encoders.Hex;
|
||||
|
||||
import java.io.BufferedWriter;
|
||||
|
@ -65,6 +67,16 @@ public class Repository {
|
|||
accountStateDB = new TrackTrie(worldState);
|
||||
}
|
||||
|
||||
public Repository(byte[] stateRoot) {
|
||||
detailsDB = new DatabaseImpl("details");
|
||||
contractDetailsDB = new TrackDatabase(detailsDB);
|
||||
stateDB = new DatabaseImpl("state");
|
||||
worldState = new Trie(stateDB.getDb());
|
||||
worldState.setRoot(stateRoot);
|
||||
accountStateDB = new TrackTrie(worldState);
|
||||
}
|
||||
|
||||
|
||||
private Repository(TrackTrie accountStateDB, TrackDatabase contractDetailsDB) {
|
||||
this.accountStateDB = accountStateDB;
|
||||
this.contractDetailsDB = contractDetailsDB;
|
||||
|
@ -208,7 +220,7 @@ public class Repository {
|
|||
this.validateAddress(addr);
|
||||
|
||||
AccountState state = getAccountState(addr);
|
||||
ContractDetails details = getContractDetails(addr);
|
||||
ContractDetails details = getContractDetails(addr);
|
||||
|
||||
if (state == null || details == null) return;
|
||||
details.put(key, value);
|
||||
|
@ -310,10 +322,13 @@ public class Repository {
|
|||
|
||||
String dir = CONFIG.dumpDir() + "/";
|
||||
|
||||
String fileName = blockNumber + ".dmp";
|
||||
String fileName = "";
|
||||
if (txHash != null)
|
||||
fileName = String.format("%d_%d_%s.dmp",
|
||||
blockNumber, txNumber, txHash.substring(0, 8));
|
||||
else
|
||||
fileName = String.format("%d_c.dmp", blockNumber);
|
||||
|
||||
|
||||
File dumpFile = new File(System.getProperty("user.dir") + "/" + dir + fileName);
|
||||
FileWriter fw = null;
|
||||
|
@ -335,24 +350,29 @@ public class Repository {
|
|||
AccountState state = getAccountState(keyBytes);
|
||||
ContractDetails details = getContractDetails(keyBytes);
|
||||
|
||||
BigInteger nonce = state.getNonce();
|
||||
BigInteger balance = state.getBalance();
|
||||
BigInteger nonce = (state != null)? state.getNonce():null;
|
||||
BigInteger balance = (state != null)? state.getBalance():null;
|
||||
|
||||
byte[] stateRoot = state.getStateRoot();
|
||||
byte[] codeHash = state.getCodeHash();
|
||||
byte[] stateRoot = (state != null)? state.getStateRoot():null;
|
||||
byte[] codeHash = (state != null)? state.getCodeHash():null;
|
||||
|
||||
byte[] code = details.getCode();
|
||||
Map<DataWord, DataWord> storage = details.getStorage();
|
||||
|
||||
String accountLine = JSONHelper.dumpLine(key.getData(),
|
||||
nonce.toByteArray(),
|
||||
balance.toByteArray(), stateRoot, codeHash, code, storage);
|
||||
(nonce != null)? BigIntegers.asUnsignedByteArray(nonce) : null,
|
||||
(nonce != null)? BigIntegers.asUnsignedByteArray(balance): null,
|
||||
stateRoot, codeHash, code, storage);
|
||||
|
||||
bw.write(accountLine);
|
||||
bw.write("\n");
|
||||
|
||||
// {address: x, nonce: n1, balance: b1, stateRoot: s1, codeHash: c1, code: c2, sotrage: [key: k1, value: v1, key:k2, value: v2 ] }
|
||||
}
|
||||
|
||||
String rootHash = Hex.toHexString(WorldManager.getInstance().getRepository().getRootHash());
|
||||
bw.write(
|
||||
String.format(" => Global State Root: [ %s ]", rootHash)
|
||||
);
|
||||
|
||||
} catch (IOException e) {
|
||||
logger.error(e.getMessage(), e);
|
||||
} finally {
|
||||
|
@ -364,6 +384,11 @@ public class Repository {
|
|||
}
|
||||
|
||||
public void close() {
|
||||
|
||||
if (worldState != null){
|
||||
worldState.sync();
|
||||
}
|
||||
|
||||
if (this.stateDB != null)
|
||||
stateDB.close();
|
||||
if (this.detailsDB != null)
|
||||
|
|
|
@ -69,4 +69,9 @@ public class TrackDatabase implements Database {
|
|||
db.delete(key);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close(){
|
||||
db.close();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -39,8 +39,8 @@ public class JSONHelper {
|
|||
|
||||
JSONArray orderFields = new JSONArray();
|
||||
orderFields.add("address: " + Hex.toHexString(address));
|
||||
orderFields.add(" nonce: " + Hex.toHexString(nonce));
|
||||
orderFields.add(" balance: " + new BigInteger(balance).toString());
|
||||
orderFields.add(" nonce: " + (nonce == null ? "00" : Hex.toHexString(nonce)));
|
||||
orderFields.add(" balance: " + (balance == null ? "00" : Hex.toHexString(balance).toString()));
|
||||
orderFields.add(" stateRoot: " + (stateRoot == null ? "" : Hex.toHexString(stateRoot)));
|
||||
orderFields.add(" codeHash: " + (codeHash == null ? "" : Hex.toHexString(codeHash)));
|
||||
orderFields.add(" code: " + (code == null ? "" : Hex.toHexString(code)));
|
||||
|
|
|
@ -69,12 +69,12 @@ public class WorldManager {
|
|||
public static WorldManager getInstance() {
|
||||
if(instance == null) {
|
||||
instance = new WorldManager();
|
||||
instance.getBlockChain().load();
|
||||
instance.blockchain.load();
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
public void applyTransaction(Transaction tx, byte[] coinbase) {
|
||||
public void applyTransaction(Block block, Transaction tx, byte[] coinbase) {
|
||||
|
||||
byte[] senderAddress = tx.getSender();
|
||||
AccountState senderAccount = repository.getAccountState(senderAddress);
|
||||
|
@ -88,7 +88,7 @@ public class WorldManager {
|
|||
|
||||
// 1. VALIDATE THE NONCE
|
||||
BigInteger nonce = senderAccount.getNonce();
|
||||
BigInteger txNonce = new BigInteger(tx.getNonce());
|
||||
BigInteger txNonce = new BigInteger(1, tx.getNonce());
|
||||
if (nonce.compareTo(txNonce) != 0) {
|
||||
if (stateLogger.isWarnEnabled())
|
||||
stateLogger.warn("Invalid nonce account.nonce={} tx.nonce={}",
|
||||
|
@ -187,10 +187,10 @@ public class WorldManager {
|
|||
|
||||
// 5. CREATE OR EXECUTE PROGRAM
|
||||
if (isContractCreation || code != null) {
|
||||
Block lastBlock = blockchain.getLastBlock();
|
||||
Block currBlock = (block == null) ? blockchain.getLastBlock() : block;
|
||||
|
||||
ProgramInvoke programInvoke = ProgramInvokeFactory
|
||||
.createProgramInvoke(tx, lastBlock, trackRepository);
|
||||
.createProgramInvoke(tx, currBlock, trackRepository);
|
||||
|
||||
VM vm = new VM();
|
||||
Program program = new Program(code, programInvoke);
|
||||
|
@ -283,7 +283,8 @@ public class WorldManager {
|
|||
|
||||
int i = 0;
|
||||
for (Transaction tx : block.getTransactionsList()) {
|
||||
applyTransaction(tx, block.getCoinbase());
|
||||
logger.info("apply block: [ {} ] tx: [ {} ] ", block.getNumber(), i);
|
||||
applyTransaction(block, tx, block.getCoinbase());
|
||||
repository.dumpState(block.getNumber(), i,
|
||||
Hex.toHexString(tx.getHash()));
|
||||
++i;
|
||||
|
@ -295,7 +296,11 @@ public class WorldManager {
|
|||
repository.addBalance(block.getCoinbase(), Block.BLOCK_REWARD);
|
||||
for (Block uncle : block.getUncleList()) {
|
||||
repository.addBalance(uncle.getCoinbase(), Block.UNCLE_REWARD);
|
||||
}
|
||||
}
|
||||
|
||||
repository.dumpState(block.getNumber(), 0,
|
||||
null);
|
||||
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
|
|
|
@ -94,7 +94,7 @@ public class MessageQueue {
|
|||
if (null != messageQueue.peek()){
|
||||
|
||||
MessageRoundtrip messageRoundtrip = messageQueue.peek();
|
||||
if (messageRoundtrip.getRetryTimes() == 0 || messageRoundtrip.hasToRetry()){
|
||||
if (messageRoundtrip.getRetryTimes() == 0 ) {// todo: retry logic || messageRoundtrip.hasToRetry()){
|
||||
|
||||
Message msg = messageRoundtrip.getMsg();
|
||||
sendToWire(msg);
|
||||
|
|
|
@ -74,11 +74,13 @@ public class EthereumProtocolHandler extends ChannelInboundHandlerAdapter {
|
|||
if (lastPongTime == 0) lastPongTime = System.currentTimeMillis();
|
||||
if (tearDown) this.cancel();
|
||||
|
||||
/* todo: temporary cancel ping rate test
|
||||
long currTime = System.currentTimeMillis();
|
||||
if (currTime - lastPongTime > 30000) {
|
||||
logger.info("No ping answer for [30 sec]");
|
||||
throw new RuntimeException("No ping return for 30 [sec]");
|
||||
}
|
||||
*/
|
||||
|
||||
sendPing();
|
||||
}
|
||||
|
@ -175,7 +177,7 @@ public class EthereumProtocolHandler extends ChannelInboundHandlerAdapter {
|
|||
|
||||
List<Transaction> txList = transactionsMessage.getTransactions();
|
||||
for(Transaction tx : txList)
|
||||
WorldManager.getInstance().applyTransaction(tx, null);
|
||||
WorldManager.getInstance().applyTransaction(null, tx, null);
|
||||
|
||||
logger.info(transactionsMessage.toString());
|
||||
if (peerListener != null) peerListener.console(transactionsMessage.toString());
|
||||
|
|
|
@ -15,7 +15,7 @@ public class TrackTrie implements TrieFacade {
|
|||
|
||||
private TrieFacade trie;
|
||||
|
||||
private boolean trackingChanges;
|
||||
private boolean trackingChanges = false;
|
||||
private Map<ByteArrayWrapper, byte[]> changes;
|
||||
private Map<ByteArrayWrapper, byte[]> deletes;
|
||||
|
||||
|
|
|
@ -27,7 +27,7 @@ public class Program {
|
|||
|
||||
Stack<DataWord> stack = new Stack<DataWord>();
|
||||
ByteBuffer memory = null;
|
||||
byte[] programAddress;
|
||||
DataWord programAddress;
|
||||
|
||||
ProgramResult result = new ProgramResult();
|
||||
|
||||
|
@ -47,7 +47,8 @@ public class Program {
|
|||
|
||||
this.invokeData = invokeData;
|
||||
this.ops = ops;
|
||||
this.programAddress = invokeData.getOwnerAddress().getLast20Bytes();
|
||||
this.programAddress = invokeData.getOwnerAddress();
|
||||
|
||||
}
|
||||
|
||||
public byte getCurrentOp() {
|
||||
|
@ -82,6 +83,7 @@ public class Program {
|
|||
}
|
||||
|
||||
public void setPC(DataWord pc) {
|
||||
|
||||
this.pc = pc.value().intValue();
|
||||
|
||||
if (this.pc == ops.length) {
|
||||
|
@ -111,6 +113,7 @@ public class Program {
|
|||
}
|
||||
|
||||
public void step() {
|
||||
|
||||
++pc;
|
||||
if (pc >= ops.length) stop();
|
||||
}
|
||||
|
@ -271,7 +274,7 @@ public class Program {
|
|||
// [5] COOK THE INVOKE AND EXECUTE
|
||||
ProgramInvoke programInvoke =
|
||||
ProgramInvokeFactory.createProgramInvoke(this, new DataWord(newAddress), DataWord.ZERO,
|
||||
new DataWord(gas), BigInteger.ZERO, null, trackRepository);
|
||||
new DataWord(gas), BigInteger.ZERO, null, trackRepository, this.invokeData.getCallDeep() + 1);
|
||||
|
||||
VM vm = new VM();
|
||||
Program program = new Program(programCode.array(), programInvoke);
|
||||
|
@ -333,8 +336,8 @@ public class Program {
|
|||
byte[] programCode = this.result.getRepository().getCode(toAddress);
|
||||
|
||||
if (logger.isInfoEnabled())
|
||||
logger.info("calling for existing contract: address={}",
|
||||
Hex.toHexString(toAddress));
|
||||
logger.info("calling for existing contract: address: [ {} ], outDataOffs: [ {} ], outDataSize: [ {} ] ",
|
||||
Hex.toHexString(toAddress), outDataOffs.longValue(), outDataSize.longValue());
|
||||
|
||||
byte[] senderAddress = this.getOwnerAddress().getLast20Bytes();
|
||||
|
||||
|
@ -380,7 +383,7 @@ public class Program {
|
|||
ProgramInvokeFactory.createProgramInvoke(this, toAddressDW,
|
||||
endowmentValue, gas, result.getRepository().getBalance(toAddress),
|
||||
data.array(),
|
||||
trackRepository);
|
||||
trackRepository, this.invokeData.getCallDeep() + 1);
|
||||
|
||||
ProgramResult result = null;
|
||||
|
||||
|
@ -458,12 +461,12 @@ public class Program {
|
|||
public void storageSave(byte[] key, byte[] val) {
|
||||
DataWord keyWord = new DataWord(key);
|
||||
DataWord valWord = new DataWord(val);
|
||||
result.getRepository().addStorageRow(this.programAddress, keyWord, valWord);
|
||||
result.getRepository().addStorageRow(this.programAddress.getLast20Bytes(), keyWord, valWord);
|
||||
}
|
||||
|
||||
public DataWord getOwnerAddress() {
|
||||
if (invokeData == null) return new DataWord( new byte[0]);
|
||||
return invokeData.getOwnerAddress();
|
||||
return this.programAddress.clone();
|
||||
}
|
||||
|
||||
public DataWord getBalance(DataWord address) {
|
||||
|
@ -477,17 +480,17 @@ public class Program {
|
|||
|
||||
public DataWord getOriginAddress() {
|
||||
if (invokeData == null) return new DataWord( new byte[0]);
|
||||
return invokeData.getOriginAddress();
|
||||
return invokeData.getOriginAddress().clone();
|
||||
}
|
||||
|
||||
public DataWord getCallerAddress() {
|
||||
if (invokeData == null) return new DataWord( new byte[0]);
|
||||
return invokeData.getCallerAddress();
|
||||
return invokeData.getCallerAddress().clone();
|
||||
}
|
||||
|
||||
public DataWord getGasPrice() {
|
||||
if (invokeData == null) return new DataWord( new byte[0]);
|
||||
return invokeData.getMinGasPrice();
|
||||
return invokeData.getMinGasPrice().clone();
|
||||
}
|
||||
|
||||
public DataWord getGas() {
|
||||
|
@ -498,12 +501,12 @@ public class Program {
|
|||
|
||||
public DataWord getCallValue() {
|
||||
if (invokeData == null) return new DataWord( new byte[0]);
|
||||
return invokeData.getCallValue();
|
||||
return invokeData.getCallValue().clone();
|
||||
}
|
||||
|
||||
public DataWord getDataSize() {
|
||||
if (invokeData == null) return new DataWord( new byte[0]);
|
||||
return invokeData.getDataSize();
|
||||
return invokeData.getDataSize().clone();
|
||||
}
|
||||
|
||||
public DataWord getDataValue(DataWord index) {
|
||||
|
@ -517,31 +520,31 @@ public class Program {
|
|||
}
|
||||
|
||||
public DataWord storageLoad(DataWord key) {
|
||||
return result.getRepository().getStorageValue(this.programAddress, key);
|
||||
return result.getRepository().getStorageValue(this.programAddress.getLast20Bytes(), key);
|
||||
}
|
||||
|
||||
public DataWord getPrevHash() {
|
||||
return invokeData.getPrevHash();
|
||||
return invokeData.getPrevHash().clone();
|
||||
}
|
||||
|
||||
public DataWord getCoinbase() {
|
||||
return invokeData.getCoinbase();
|
||||
return invokeData.getCoinbase().clone();
|
||||
}
|
||||
|
||||
public DataWord getTimestamp() {
|
||||
return invokeData.getTimestamp();
|
||||
return invokeData.getTimestamp().clone();
|
||||
}
|
||||
|
||||
public DataWord getNumber() {
|
||||
return invokeData.getNumber();
|
||||
return invokeData.getNumber().clone();
|
||||
}
|
||||
|
||||
public DataWord getDifficulty() {
|
||||
return invokeData.getDifficulty();
|
||||
return invokeData.getDifficulty().clone();
|
||||
}
|
||||
|
||||
public DataWord getGaslimit() {
|
||||
return invokeData.getGaslimit();
|
||||
return invokeData.getGaslimit().clone();
|
||||
}
|
||||
|
||||
|
||||
|
@ -564,7 +567,8 @@ public class Program {
|
|||
}
|
||||
if (stackData.length() > 0) stackData.insert(0, "\n");
|
||||
|
||||
ContractDetails contractDetails = this.result.getRepository().getContractDetails(this.programAddress);
|
||||
ContractDetails contractDetails = this.result.getRepository().
|
||||
getContractDetails(this.programAddress.getLast20Bytes());
|
||||
StringBuilder storageData = new StringBuilder();
|
||||
for (DataWord key : contractDetails.getStorage().keySet()) {
|
||||
storageData.append(" ").append(key).append(" -> ").
|
||||
|
|
|
@ -31,4 +31,6 @@ public interface ProgramInvoke {
|
|||
|
||||
public boolean byTransaction();
|
||||
boolean byTestingSuite();
|
||||
|
||||
public int getCallDeep();
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ package org.ethereum.vm;
|
|||
import org.ethereum.core.Block;
|
||||
import org.ethereum.core.Transaction;
|
||||
import org.ethereum.db.Repository;
|
||||
import org.ethereum.manager.WorldManager;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.spongycastle.util.encoders.Hex;
|
||||
|
@ -20,9 +21,10 @@ public class ProgramInvokeFactory {
|
|||
private static Logger logger = LoggerFactory.getLogger("VM");
|
||||
|
||||
// Invocation by the wire tx
|
||||
public static ProgramInvoke createProgramInvoke(Transaction tx, Block lastBlock, Repository repository) {
|
||||
public static ProgramInvoke createProgramInvoke(Transaction tx, Block block, Repository repository) {
|
||||
|
||||
// https://ethereum.etherpad.mozilla.org/26
|
||||
Block lastBlock = WorldManager.getInstance().getBlockChain().getLastBlock();
|
||||
|
||||
/*** ADDRESS op ***/
|
||||
// YP: Get address of currently executing account.
|
||||
|
@ -58,19 +60,19 @@ public class ProgramInvokeFactory {
|
|||
byte[] lastHash = lastBlock.getHash();
|
||||
|
||||
/*** COINBASE op ***/
|
||||
byte[] coinbase = lastBlock.getCoinbase();
|
||||
byte[] coinbase = block.getCoinbase();
|
||||
|
||||
/*** TIMESTAMP op ***/
|
||||
long timestamp = lastBlock.getTimestamp();
|
||||
long timestamp = block.getTimestamp();
|
||||
|
||||
/*** NUMBER op ***/
|
||||
long number = lastBlock.getNumber();
|
||||
long number = block.getNumber();
|
||||
|
||||
/*** DIFFICULTY op ***/
|
||||
byte[] difficulty = lastBlock.getDifficulty();
|
||||
byte[] difficulty = block.getDifficulty();
|
||||
|
||||
/*** GASLIMIT op ***/
|
||||
long gaslimit = lastBlock.getGasLimit();
|
||||
long gaslimit = block.getGasLimit();
|
||||
|
||||
if (logger.isInfoEnabled()) {
|
||||
logger.info("Program invocation: \n" +
|
||||
|
@ -121,7 +123,7 @@ public class ProgramInvokeFactory {
|
|||
public static ProgramInvoke createProgramInvoke(Program program, DataWord toAddress,
|
||||
DataWord inValue, DataWord inGas,
|
||||
BigInteger balanceInt, byte[] dataIn,
|
||||
Repository repository) {
|
||||
Repository repository, int callDeep) {
|
||||
|
||||
DataWord address = toAddress;
|
||||
DataWord origin = program.getOriginAddress();
|
||||
|
@ -175,6 +177,6 @@ public class ProgramInvokeFactory {
|
|||
|
||||
return new ProgramInvokeImpl(address, origin, caller, balance, gasPrice, gas, callValue,
|
||||
data, lastHash, coinbase, timestamp, number, difficulty, gasLimit,
|
||||
repository);
|
||||
repository, callDeep);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,7 +13,8 @@ import java.util.Map;
|
|||
public class ProgramInvokeImpl implements ProgramInvoke {
|
||||
|
||||
/*** TRANSACTION env ***/
|
||||
private DataWord address, origin, caller,
|
||||
private DataWord address;
|
||||
private DataWord origin, caller,
|
||||
balance, gas, gasPrice, callValue;
|
||||
|
||||
byte[] msgData;
|
||||
|
@ -27,11 +28,12 @@ public class ProgramInvokeImpl implements ProgramInvoke {
|
|||
private Repository repository;
|
||||
private boolean byTransaction = true;
|
||||
private boolean byTestingSuite = false;
|
||||
private int callDeep = 0;
|
||||
|
||||
public ProgramInvokeImpl(DataWord address, DataWord origin, DataWord caller, DataWord balance,
|
||||
DataWord gasPrice, DataWord gas, DataWord callValue, byte[] msgData,
|
||||
DataWord lastHash, DataWord coinbase, DataWord timestamp, DataWord number, DataWord difficulty,
|
||||
DataWord gaslimit, Repository repository) {
|
||||
DataWord gaslimit, Repository repository, int callDeep) {
|
||||
|
||||
// Transaction env
|
||||
this.address = address;
|
||||
|
@ -53,6 +55,7 @@ public class ProgramInvokeImpl implements ProgramInvoke {
|
|||
|
||||
this.repository = repository;
|
||||
this.byTransaction = false;
|
||||
this.callDeep = callDeep;
|
||||
}
|
||||
|
||||
public ProgramInvokeImpl(byte[] address, byte[] origin, byte[] caller, byte[] balance,
|
||||
|
@ -221,6 +224,11 @@ public class ProgramInvokeImpl implements ProgramInvoke {
|
|||
return byTestingSuite;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCallDeep() {
|
||||
return this.callDeep;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
|
@ -251,25 +259,27 @@ public class ProgramInvokeImpl implements ProgramInvoke {
|
|||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = address != null ? address.hashCode() : 0;
|
||||
result = 31 * result + (origin != null ? origin.hashCode() : 0);
|
||||
result = 31 * result + (caller != null ? caller.hashCode() : 0);
|
||||
result = 31 * result + (balance != null ? balance.hashCode() : 0);
|
||||
result = 31 * result + (gas != null ? gas.hashCode() : 0);
|
||||
result = 31 * result + (gasPrice != null ? gasPrice.hashCode() : 0);
|
||||
result = 31 * result + (callValue != null ? callValue.hashCode() : 0);
|
||||
result = 31 * result + (msgData != null ? Arrays.hashCode(msgData) : 0);
|
||||
result = 31 * result + (prevHash != null ? prevHash.hashCode() : 0);
|
||||
result = 31 * result + (coinbase != null ? coinbase.hashCode() : 0);
|
||||
result = 31 * result + (timestamp != null ? timestamp.hashCode() : 0);
|
||||
result = 31 * result + (number != null ? number.hashCode() : 0);
|
||||
result = 31 * result + (difficulty != null ? difficulty.hashCode() : 0);
|
||||
result = 31 * result + (gaslimit != null ? gaslimit.hashCode() : 0);
|
||||
result = 31 * result + (storage != null ? storage.hashCode() : 0);
|
||||
result = 31 * result + (repository != null ? repository.hashCode() : 0);
|
||||
result = 31 * result + (byTransaction ? 1 : 0);
|
||||
result = 31 * result + (byTestingSuite ? 1 : 0);
|
||||
return result;
|
||||
public String toString() {
|
||||
return "ProgramInvokeImpl{" +
|
||||
"address=" + address +
|
||||
", origin=" + origin +
|
||||
", caller=" + caller +
|
||||
", balance=" + balance +
|
||||
", gas=" + gas +
|
||||
", gasPrice=" + gasPrice +
|
||||
", callValue=" + callValue +
|
||||
", msgData=" + Arrays.toString(msgData) +
|
||||
", prevHash=" + prevHash +
|
||||
", coinbase=" + coinbase +
|
||||
", timestamp=" + timestamp +
|
||||
", number=" + number +
|
||||
", difficulty=" + difficulty +
|
||||
", gaslimit=" + gaslimit +
|
||||
", storage=" + storage +
|
||||
", repository=" + repository +
|
||||
", byTransaction=" + byTransaction +
|
||||
", byTestingSuite=" + byTestingSuite +
|
||||
", callDeep=" + callDeep +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
|
|
|
@ -187,6 +187,8 @@ public class ProgramInvokeMockImpl implements ProgramInvoke {
|
|||
this.repository = repository;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public int getCallDeep() {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,10 +4,13 @@ import org.ethereum.crypto.HashUtil;
|
|||
import org.ethereum.vm.Program.OutOfGasException;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.spongycastle.util.encoders.Hex;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import static org.ethereum.vm.OpCode.CALL;
|
||||
import static org.ethereum.vm.OpCode.CREATE;
|
||||
import static org.ethereum.vm.OpCode.PUSH1;
|
||||
|
||||
/**
|
||||
|
@ -59,8 +62,6 @@ public class VM {
|
|||
|
||||
byte op = program.getCurrentOp();
|
||||
program.setLastOp(op);
|
||||
logger.info("[ {} ] Op: [ {} ] Gas: [ {} ]" ,program.getPC(),
|
||||
OpCode.code(op).name(), program.getGas().longValue());
|
||||
|
||||
int oldMemSize = program.getMemSize();
|
||||
|
||||
|
@ -89,6 +90,7 @@ public class VM {
|
|||
break;
|
||||
}
|
||||
|
||||
String hint = "";
|
||||
switch (OpCode.code(op)) {
|
||||
/**
|
||||
* Stop and Arithmetic Operations
|
||||
|
@ -100,13 +102,22 @@ public class VM {
|
|||
case ADD:{
|
||||
DataWord word1 = program.stackPop();
|
||||
DataWord word2 = program.stackPop();
|
||||
|
||||
if (logger.isInfoEnabled())
|
||||
hint = word1.longValue() + " + " + word2.longValue();
|
||||
|
||||
word1.add(word2);
|
||||
program.stackPush(word1);
|
||||
program.step();
|
||||
|
||||
} break;
|
||||
case MUL:{
|
||||
DataWord word1 = program.stackPop();
|
||||
DataWord word2 = program.stackPop();
|
||||
|
||||
if (logger.isInfoEnabled())
|
||||
hint = word1.longValue() + " * " + word2.longValue();
|
||||
|
||||
word1.mul(word2);
|
||||
program.stackPush(word1);
|
||||
program.step();
|
||||
|
@ -114,6 +125,10 @@ public class VM {
|
|||
case SUB:{
|
||||
DataWord word1 = program.stackPop();
|
||||
DataWord word2 = program.stackPop();
|
||||
|
||||
if (logger.isInfoEnabled())
|
||||
hint = word1.longValue() + " - " + word2.longValue();
|
||||
|
||||
word1.sub(word2);
|
||||
program.stackPush(word1);
|
||||
program.step();
|
||||
|
@ -121,6 +136,10 @@ public class VM {
|
|||
case DIV:{
|
||||
DataWord word1 = program.stackPop();
|
||||
DataWord word2 = program.stackPop();
|
||||
|
||||
if (logger.isInfoEnabled())
|
||||
hint = word1.longValue() + " / " + word2.longValue();
|
||||
|
||||
word1.div(word2);
|
||||
program.stackPush(word1);
|
||||
program.step();
|
||||
|
@ -128,6 +147,10 @@ public class VM {
|
|||
case SDIV:{
|
||||
DataWord word1 = program.stackPop();
|
||||
DataWord word2 = program.stackPop();
|
||||
|
||||
if (logger.isInfoEnabled())
|
||||
hint = word1.sValue() + " / " + word2.sValue();
|
||||
|
||||
word1.sDiv(word2);
|
||||
program.stackPush(word1);
|
||||
program.step();
|
||||
|
@ -135,6 +158,10 @@ public class VM {
|
|||
case MOD:{
|
||||
DataWord word1 = program.stackPop();
|
||||
DataWord word2 = program.stackPop();
|
||||
|
||||
if (logger.isInfoEnabled())
|
||||
hint = word1.longValue() + " % " + word2.longValue();
|
||||
|
||||
word1.mod(word2);
|
||||
program.stackPush(word1);
|
||||
program.step();
|
||||
|
@ -142,6 +169,10 @@ public class VM {
|
|||
case SMOD:{
|
||||
DataWord word1 = program.stackPop();
|
||||
DataWord word2 = program.stackPop();
|
||||
|
||||
if (logger.isInfoEnabled())
|
||||
hint = word1.sValue() + " #% " + word2.sValue();
|
||||
|
||||
word1.sMod(word2);
|
||||
program.stackPush(word1);
|
||||
program.step();
|
||||
|
@ -149,6 +180,10 @@ public class VM {
|
|||
case EXP:{
|
||||
DataWord word1 = program.stackPop();
|
||||
DataWord word2 = program.stackPop();
|
||||
|
||||
if (logger.isInfoEnabled())
|
||||
hint = word1.longValue() + " ** " + word2.longValue();
|
||||
|
||||
word1.exp(word2);
|
||||
program.stackPush(word1);
|
||||
program.step();
|
||||
|
@ -156,6 +191,10 @@ public class VM {
|
|||
case NEG:{
|
||||
DataWord word1 = program.stackPop();
|
||||
word1.negate();
|
||||
|
||||
if (logger.isInfoEnabled())
|
||||
hint = "" + word1.longValue();
|
||||
|
||||
program.stackPush(word1);
|
||||
program.step();
|
||||
} break;
|
||||
|
@ -163,6 +202,10 @@ public class VM {
|
|||
// TODO: can be improved by not using BigInteger
|
||||
DataWord word1 = program.stackPop();
|
||||
DataWord word2 = program.stackPop();
|
||||
|
||||
if (logger.isInfoEnabled())
|
||||
hint = word1.longValue() + " < " + word2.longValue();
|
||||
|
||||
if (word1.value().compareTo(word2.value()) == -1) {
|
||||
word1.and(DataWord.ZERO);
|
||||
word1.getData()[31] = 1;
|
||||
|
@ -176,6 +219,10 @@ public class VM {
|
|||
// TODO: can be improved by not using BigInteger
|
||||
DataWord word1 = program.stackPop();
|
||||
DataWord word2 = program.stackPop();
|
||||
|
||||
if (logger.isInfoEnabled())
|
||||
hint = word1.sValue() + " < " + word2.sValue();
|
||||
|
||||
if (word1.sValue().compareTo(word2.sValue()) == -1) {
|
||||
word1.and(DataWord.ZERO);
|
||||
word1.getData()[31] = 1;
|
||||
|
@ -189,6 +236,10 @@ public class VM {
|
|||
// TODO: can be improved by not using BigInteger
|
||||
DataWord word1 = program.stackPop();
|
||||
DataWord word2 = program.stackPop();
|
||||
|
||||
if (logger.isInfoEnabled())
|
||||
hint = word1.sValue() + " > " + word2.sValue();
|
||||
|
||||
if (word1.sValue().compareTo(word2.sValue()) == 1) {
|
||||
word1.and(DataWord.ZERO);
|
||||
word1.getData()[31] = 1;
|
||||
|
@ -202,6 +253,10 @@ public class VM {
|
|||
// TODO: can be improved by not using BigInteger
|
||||
DataWord word1 = program.stackPop();
|
||||
DataWord word2 = program.stackPop();
|
||||
|
||||
if (logger.isInfoEnabled())
|
||||
hint = word1.longValue() + " < " + word2.longValue();
|
||||
|
||||
if (word1.value().compareTo(word2.value()) == 1) {
|
||||
word1.and(DataWord.ZERO);
|
||||
word1.getData()[31] = 1;
|
||||
|
@ -214,6 +269,10 @@ public class VM {
|
|||
case EQ:{
|
||||
DataWord word1 = program.stackPop();
|
||||
DataWord word2 = program.stackPop();
|
||||
|
||||
if (logger.isInfoEnabled())
|
||||
hint = word1.longValue() + " = " + word2.longValue();
|
||||
|
||||
if (word1.xor(word2).isZero()) {
|
||||
word1.and(DataWord.ZERO);
|
||||
word1.getData()[31] = 1;
|
||||
|
@ -230,6 +289,10 @@ public class VM {
|
|||
} else {
|
||||
word1.and(DataWord.ZERO);
|
||||
}
|
||||
|
||||
if (logger.isInfoEnabled())
|
||||
hint = "" + word1.longValue();
|
||||
|
||||
program.stackPush(word1);
|
||||
program.step();
|
||||
} break;
|
||||
|
@ -240,6 +303,10 @@ public class VM {
|
|||
case AND:{
|
||||
DataWord word1 = program.stackPop();
|
||||
DataWord word2 = program.stackPop();
|
||||
|
||||
if (logger.isInfoEnabled())
|
||||
hint = word1.longValue() + " && " + word2.longValue();
|
||||
|
||||
word1.and(word2);
|
||||
program.stackPush(word1);
|
||||
program.step();
|
||||
|
@ -247,6 +314,10 @@ public class VM {
|
|||
case OR: {
|
||||
DataWord word1 = program.stackPop();
|
||||
DataWord word2 = program.stackPop();
|
||||
|
||||
if (logger.isInfoEnabled())
|
||||
hint = word1.longValue() + " || " + word2.longValue();
|
||||
|
||||
word1.or(word2);
|
||||
program.stackPush(word1);
|
||||
program.step();
|
||||
|
@ -254,6 +325,10 @@ public class VM {
|
|||
case XOR: {
|
||||
DataWord word1 = program.stackPop();
|
||||
DataWord word2 = program.stackPop();
|
||||
|
||||
if (logger.isInfoEnabled())
|
||||
hint = word1.longValue() + " ^ " + word2.longValue();
|
||||
|
||||
word1.xor(word2);
|
||||
program.stackPush(word1);
|
||||
program.step();
|
||||
|
@ -270,6 +345,10 @@ public class VM {
|
|||
} else {
|
||||
result = new DataWord();
|
||||
}
|
||||
|
||||
if (logger.isInfoEnabled())
|
||||
hint = "" + result.longValue();
|
||||
|
||||
program.stackPush(result);
|
||||
program.step();
|
||||
} break;
|
||||
|
@ -285,6 +364,9 @@ public class VM {
|
|||
byte[] encoded = HashUtil.sha3(buffer.array());
|
||||
DataWord word = new DataWord(encoded);
|
||||
|
||||
if (logger.isInfoEnabled())
|
||||
hint = word.toString();
|
||||
|
||||
program.stackPush(word);
|
||||
program.step();
|
||||
} break;
|
||||
|
@ -294,27 +376,47 @@ public class VM {
|
|||
*/
|
||||
case ADDRESS:{
|
||||
DataWord address = program.getOwnerAddress();
|
||||
|
||||
if (logger.isInfoEnabled())
|
||||
hint = address.toString();
|
||||
|
||||
program.stackPush(address);
|
||||
program.step();
|
||||
} break;
|
||||
case BALANCE:{
|
||||
DataWord address = program.stackPop();
|
||||
DataWord balance = program.getBalance(address);
|
||||
|
||||
if (logger.isInfoEnabled())
|
||||
hint = "address: " + address.toString() + " balance: " + balance.longValue();
|
||||
|
||||
program.stackPush(balance);
|
||||
program.step();
|
||||
} break;
|
||||
case ORIGIN:{
|
||||
DataWord originAddress = program.getOriginAddress();
|
||||
|
||||
if (logger.isInfoEnabled())
|
||||
hint = "address: " + originAddress.toString();
|
||||
|
||||
program.stackPush(originAddress);
|
||||
program.step();
|
||||
} break;
|
||||
case CALLER:{
|
||||
DataWord callerAddress = program.getCallerAddress();
|
||||
|
||||
if (logger.isInfoEnabled())
|
||||
hint = "address: " + callerAddress.toString();
|
||||
|
||||
program.stackPush(callerAddress);
|
||||
program.step();
|
||||
} break;
|
||||
case CALLVALUE:{
|
||||
DataWord callValue = program.getCallValue();
|
||||
|
||||
if (logger.isInfoEnabled())
|
||||
hint = "value: " + callValue.toString();
|
||||
|
||||
program.stackPush(callValue);
|
||||
program.step();
|
||||
} break;
|
||||
|
@ -322,11 +424,18 @@ public class VM {
|
|||
DataWord dataOffs = program.stackPop();
|
||||
DataWord value = program.getDataValue(dataOffs);
|
||||
|
||||
if (logger.isInfoEnabled())
|
||||
hint = "data: " + value.toString();
|
||||
|
||||
program.stackPush(value);
|
||||
program.step();
|
||||
} break;
|
||||
case CALLDATASIZE:{
|
||||
DataWord dataSize = program.getDataSize();
|
||||
|
||||
if (logger.isInfoEnabled())
|
||||
hint = "size: " + dataSize.longValue();
|
||||
|
||||
program.stackPush(dataSize);
|
||||
program.step();
|
||||
} break;
|
||||
|
@ -336,11 +445,19 @@ public class VM {
|
|||
DataWord lengthData = program.stackPop();
|
||||
|
||||
byte[] msgData = program.getDataCopy(dataOffsetData, lengthData);
|
||||
|
||||
if (logger.isInfoEnabled())
|
||||
hint = "data: " + Hex.toHexString(msgData);
|
||||
|
||||
program.memorySave(memOffsetData.data, msgData);
|
||||
program.step();
|
||||
} break;
|
||||
case CODESIZE:{
|
||||
DataWord length = new DataWord(program.ops.length);
|
||||
|
||||
if (logger.isInfoEnabled())
|
||||
hint = "size: " + length.longValue();
|
||||
|
||||
program.stackPush(length);
|
||||
program.step();
|
||||
} break;
|
||||
|
@ -360,11 +477,18 @@ public class VM {
|
|||
byte[] code = new byte[length];
|
||||
System.arraycopy(program.ops, codeOffset, code, 0, length);
|
||||
|
||||
if (logger.isInfoEnabled())
|
||||
hint = "code: " + Hex.toHexString(code);
|
||||
|
||||
program.memorySave(memOffsetData.getData(), code);
|
||||
program.step();
|
||||
} break;
|
||||
case GASPRICE:{
|
||||
DataWord gasPrice = program.getGasPrice();
|
||||
|
||||
if (logger.isInfoEnabled())
|
||||
hint = "price: " + gasPrice.toString();
|
||||
|
||||
program.stackPush(gasPrice);
|
||||
program.step();
|
||||
} break;
|
||||
|
@ -374,31 +498,55 @@ public class VM {
|
|||
*/
|
||||
case PREVHASH: {
|
||||
DataWord prevHash = program.getPrevHash();
|
||||
|
||||
if (logger.isInfoEnabled())
|
||||
hint = "prevHash: " + prevHash;
|
||||
|
||||
program.stackPush(prevHash);
|
||||
program.step();
|
||||
} break;
|
||||
case COINBASE: {
|
||||
DataWord coinbase = program.getCoinbase();
|
||||
|
||||
if (logger.isInfoEnabled())
|
||||
hint = "coinbase: " + coinbase;
|
||||
|
||||
program.stackPush(coinbase);
|
||||
program.step();
|
||||
} break;
|
||||
case TIMESTAMP:{
|
||||
DataWord timestamp = program.getTimestamp();
|
||||
|
||||
if (logger.isInfoEnabled())
|
||||
hint = "timestamp: " + timestamp.longValue();
|
||||
|
||||
program.stackPush(timestamp);
|
||||
program.step();
|
||||
} break;
|
||||
case NUMBER:{
|
||||
DataWord number = program.getNumber();
|
||||
|
||||
if (logger.isInfoEnabled())
|
||||
hint = "number: " + number.longValue();
|
||||
|
||||
program.stackPush(number);
|
||||
program.step();
|
||||
} break;
|
||||
case DIFFICULTY:{
|
||||
DataWord difficulty = program.getDifficulty();
|
||||
|
||||
if (logger.isInfoEnabled())
|
||||
hint = "difficulty: " + difficulty;
|
||||
|
||||
program.stackPush(difficulty);
|
||||
program.step();
|
||||
} break;
|
||||
case GASLIMIT:{
|
||||
DataWord gaslimit = program.getGaslimit();
|
||||
|
||||
if (logger.isInfoEnabled())
|
||||
hint = "gaslimit: " + gaslimit;
|
||||
|
||||
program.stackPush(gaslimit);
|
||||
program.step();
|
||||
} break;
|
||||
|
@ -423,12 +571,20 @@ public class VM {
|
|||
case MLOAD:{
|
||||
DataWord addr = program.stackPop();
|
||||
DataWord data = program.memoryLoad(addr);
|
||||
|
||||
if (logger.isInfoEnabled())
|
||||
hint = "data: " + data;
|
||||
|
||||
program.stackPush(data);
|
||||
program.step();
|
||||
} break;
|
||||
case MSTORE:{
|
||||
DataWord addr = program.stackPop();
|
||||
DataWord value = program.stackPop();
|
||||
|
||||
if (logger.isInfoEnabled())
|
||||
hint = "addr: " + addr + " value: " + value;
|
||||
|
||||
program.memorySave(addr, value);
|
||||
program.step();
|
||||
} break;
|
||||
|
@ -442,6 +598,10 @@ public class VM {
|
|||
case SLOAD:{
|
||||
DataWord key = program.stackPop();
|
||||
DataWord val = program.storageLoad(key);
|
||||
|
||||
if (logger.isInfoEnabled())
|
||||
hint = "key: " + key + " value: " + val;
|
||||
|
||||
if (val == null) {
|
||||
val = key.and(DataWord.ZERO);
|
||||
}
|
||||
|
@ -452,6 +612,9 @@ public class VM {
|
|||
DataWord addr = program.stackPop();
|
||||
DataWord value = program.stackPop();
|
||||
|
||||
if (logger.isInfoEnabled())
|
||||
hint = "addr: " + addr + " value: " + value;
|
||||
|
||||
// for gas calculations [YP 9.2]
|
||||
DataWord oldValue = program.storageLoad(addr);
|
||||
program.storageSave(addr, value);
|
||||
|
@ -465,6 +628,10 @@ public class VM {
|
|||
} break;
|
||||
case JUMP:{
|
||||
DataWord pos = program.stackPop();
|
||||
|
||||
if (logger.isInfoEnabled())
|
||||
hint = "~> " + pos.longValue();
|
||||
|
||||
program.setPC(pos);
|
||||
} break;
|
||||
case JUMPI:{
|
||||
|
@ -476,21 +643,37 @@ public class VM {
|
|||
} else{
|
||||
program.step();
|
||||
}
|
||||
|
||||
if (logger.isInfoEnabled())
|
||||
hint = "~> " + program.getPC();
|
||||
|
||||
} break;
|
||||
case PC:{
|
||||
int pc = program.getPC();
|
||||
DataWord pcWord = new DataWord(pc);
|
||||
|
||||
if (logger.isInfoEnabled())
|
||||
hint = pcWord.toString();
|
||||
|
||||
program.stackPush(pcWord);
|
||||
program.step();
|
||||
} break;
|
||||
case MSIZE:{
|
||||
int memSize = program.getMemSize();
|
||||
DataWord wordMemSize = new DataWord(memSize);
|
||||
|
||||
if (logger.isInfoEnabled())
|
||||
hint = "" + memSize;
|
||||
|
||||
program.stackPush(wordMemSize);
|
||||
program.step();
|
||||
} break;
|
||||
case GAS:{
|
||||
DataWord gas = program.getGas();
|
||||
|
||||
if (logger.isInfoEnabled())
|
||||
hint = "" + gas;
|
||||
|
||||
program.stackPush(gas);
|
||||
program.step();
|
||||
} break;
|
||||
|
@ -503,6 +686,8 @@ public class VM {
|
|||
int nPush = op - PUSH1.val() + 1;
|
||||
|
||||
byte[] data = program.sweep(nPush);
|
||||
hint = "" + Hex.toHexString(data);
|
||||
|
||||
program.stackPush(data);
|
||||
} break;
|
||||
case CREATE:{
|
||||
|
@ -510,6 +695,10 @@ public class VM {
|
|||
DataWord inOffset = program.stackPop();
|
||||
DataWord inSize = program.stackPop();
|
||||
|
||||
if (logger.isInfoEnabled())
|
||||
logger.info("[ {} ] Op: [ {} ] Gas: [ {} ] Deep: [ {} ] Hint: [ {} ]" ,program.getPC(),
|
||||
OpCode.code(op).name(), program.getGas().longValue(),
|
||||
program.invokeData.getCallDeep(), hint);
|
||||
program.createContract(value, inOffset, inSize);
|
||||
|
||||
program.step();
|
||||
|
@ -525,6 +714,11 @@ public class VM {
|
|||
DataWord outDataOffs = program.stackPop();
|
||||
DataWord outDataSize = program.stackPop();
|
||||
|
||||
if (logger.isInfoEnabled())
|
||||
logger.info("[ {} ] Op: [ {} ] Gas: [ {} ] Deep: [ {} ] Hint: [ {} ]" ,program.getPC(),
|
||||
OpCode.code(op).name(), program.getGas().longValue(),
|
||||
program.invokeData.getCallDeep(), hint);
|
||||
|
||||
program.callToAddress(gas, toAddress, value, inDataOffs, inDataSize,outDataOffs, outDataSize);
|
||||
|
||||
program.step();
|
||||
|
@ -536,6 +730,9 @@ public class VM {
|
|||
ByteBuffer hReturn = program.memoryChunk(offset, size);
|
||||
program.setHReturn(hReturn);
|
||||
|
||||
if (logger.isInfoEnabled())
|
||||
hint = "data: " + Hex.toHexString(hReturn.array());
|
||||
|
||||
program.step();
|
||||
program.stop();
|
||||
} break;
|
||||
|
@ -548,6 +745,13 @@ public class VM {
|
|||
}
|
||||
}
|
||||
|
||||
if (logger.isInfoEnabled())
|
||||
if (!OpCode.code(op).equals(CALL) && !OpCode.code(op).equals(CREATE))
|
||||
logger.info("[ {} ] Op: [ {} ] Gas: [ {} ] Deep: [ {} ] Hint: [ {} ]" ,program.getPC(),
|
||||
OpCode.code(op).name(), program.getGas().longValue(),
|
||||
program.invokeData.getCallDeep(), hint);
|
||||
|
||||
|
||||
// memory gas calc
|
||||
int newMemSize = program.getMemSize();
|
||||
int memoryUsage = (newMemSize - oldMemSize) /32;
|
||||
|
@ -576,6 +780,7 @@ public class VM {
|
|||
program.spendGas(GasCost.TRANSACTION, "TRANSACTION");
|
||||
program.spendGas(GasCost.TXDATA * program.invokeData.getDataSize().intValue(), "DATA");
|
||||
}
|
||||
|
||||
while(!program.isStopped())
|
||||
this.step(program);
|
||||
} catch (RuntimeException e) {
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
# Root logger option
|
||||
log4j.rootLogger=DEBUG, stdout, file
|
||||
|
||||
# Direct log messages to stdout
|
||||
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
|
||||
log4j.appender.stdout.Target=System.out
|
||||
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
|
||||
log4j.appender.stdout.layout.ConversionPattern= %d{HH:mm:ss} [%c{1}] %m%n
|
||||
|
||||
log4j.appender.file=org.apache.log4j.rolling.RollingFileAppender
|
||||
log4j.appender.file.layout=org.apache.log4j.PatternLayout
|
||||
log4j.appender.file.layout.ConversionPattern= %d{HH:mm:ss} [%c{1}] %m%n
|
||||
log4j.appender.file.RollingPolicy=org.apache.log4j.rolling.TimeBasedRollingPolicy
|
||||
log4j.appender.file.RollingPolicy.FileNamePattern=./logs/ethereum_%d{yyyy-MM-dd}_h%d{HH}.log
|
||||
|
||||
# filter noisy classes
|
||||
log4j.logger.org.ethereum.core = ERROR
|
||||
log4j.logger.org.ethereum.net = ERROR
|
||||
log4j.logger.org.ethereum.db = ERROR
|
||||
log4j.logger.peerdiscovery = ERROR
|
||||
log4j.logger.java.nio = ERROR
|
||||
log4j.logger.io.netty = ERROR
|
||||
log4j.logger.wire = ERROR
|
||||
log4j.logger.VM = DEBUG
|
||||
log4j.logger.main = INFO
|
||||
log4j.logger.state = ERROR
|
||||
log4j.logger.repository = DEBUG
|
||||
log4j.logger.blockchain = DEBUG
|
||||
log4j.logger.ui = ERROR
|
||||
log4j.logger.gas = ERROR
|
||||
|
|
@ -772,8 +772,15 @@ public class RLPTest {
|
|||
byte[] output = RLP.encodeList(rlpKeysList, rlpValuesList, rlpCode);
|
||||
|
||||
assertEquals(expectedOutput, Hex.toHexString(output));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@Test
|
||||
public void encodeBigIntegerEdge_1(){
|
||||
|
||||
BigInteger integer = new BigInteger("80", 10);
|
||||
byte[] encodedData = RLP.encodeBigInteger(integer);
|
||||
System.out.println(Hex.toHexString(encodedData));
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue