/*
* Copyright (c) [2016] [ <ether.camp> ]
* This file is part of the ethereumJ library.
*
* The ethereumJ library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* The ethereumJ library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with the ethereumJ library. If not, see <http://www.gnu.org/licenses/>.
*/
package org.ethereum.vm.program.invoke;
import org.ethereum.core.Repository;
import org.ethereum.db.BlockStore;
import org.ethereum.vm.DataWord;
import java.math.BigInteger;
import java.util.Arrays;
import java.util.Map;
/**
* @author Roman Mandeleil
* @since 03.06.2014
*/
public class ProgramInvokeImpl implements ProgramInvoke {
private BlockStore blockStore;
/**
* TRANSACTION env **
*/
private final DataWord address;
private final DataWord origin, caller,
balance, gas, gasPrice, callValue;
private final long gasLong;
byte[] msgData;
/**
* BLOCK env **
*/
private final DataWord prevHash, coinbase, timestamp,
number, difficulty, gaslimit;
private Map<DataWord, DataWord> storage;
private final 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, int callDeep, BlockStore blockStore, boolean byTestingSuite) {
// Transaction env
this.address = address;
this.origin = origin;
this.caller = caller;
this.balance = balance;
this.gasPrice = gasPrice;
this.gas = gas;
this.gasLong = this.gas.longValueSafe();
this.callValue = callValue;
this.msgData = msgData;
// last Block env
this.prevHash = lastHash;
this.coinbase = coinbase;
this.timestamp = timestamp;
this.number = number;
this.difficulty = difficulty;
this.gaslimit = gaslimit;
this.repository = repository;
this.byTransaction = false;
this.callDeep = callDeep;
this.blockStore = blockStore;
this.byTestingSuite = byTestingSuite;
}
public ProgramInvokeImpl(byte[] address, byte[] origin, byte[] caller, byte[] balance,
byte[] gasPrice, byte[] gas, byte[] callValue, byte[] msgData,
byte[] lastHash, byte[] coinbase, long timestamp, long number, byte[] difficulty,
byte[] gaslimit,
Repository repository, BlockStore blockStore, boolean byTestingSuite) {
this(address, origin, caller, balance, gasPrice, gas, callValue, msgData, lastHash, coinbase,
timestamp, number, difficulty, gaslimit, repository, blockStore);
this.byTestingSuite = byTestingSuite;
}
public ProgramInvokeImpl(byte[] address, byte[] origin, byte[] caller, byte[] balance,
byte[] gasPrice, byte[] gas, byte[] callValue, byte[] msgData,
byte[] lastHash, byte[] coinbase, long timestamp, long number, byte[] difficulty,
byte[] gaslimit,
Repository repository, BlockStore blockStore) {
// Transaction env
this.address = new DataWord(address);
this.origin = new DataWord(origin);
this.caller = new DataWord(caller);
this.balance = new DataWord(balance);
this.gasPrice = new DataWord(gasPrice);
this.gas = new DataWord(gas);
this.gasLong = this.gas.longValueSafe();
this.callValue = new DataWord(callValue);
this.msgData = msgData;
// last Block env
this.prevHash = new DataWord(lastHash);
this.coinbase = new DataWord(coinbase);
this.timestamp = new DataWord(timestamp);
this.number = new DataWord(number);
this.difficulty = new DataWord(difficulty);
this.gaslimit = new DataWord(gaslimit);
this.repository = repository;
this.blockStore = blockStore;
}
/* ADDRESS op */
public DataWord getOwnerAddress() {
return address;
}
/* BALANCE op */
public DataWord getBalance() {
return balance;
}
/* ORIGIN op */
public DataWord getOriginAddress() {
return origin;
}
/* CALLER op */
public DataWord getCallerAddress() {
return caller;
}
/* GASPRICE op */
public DataWord getMinGasPrice() {
return gasPrice;
}
/* GAS op */
public DataWord getGas() {
return gas;
}
@Override
public long getGasLong() {
return gasLong;
}
/* CALLVALUE op */
public DataWord getCallValue() {
return callValue;
}
/*****************/
/*** msg data ***/
/*****************/
/* NOTE: In the protocol there is no restriction on the maximum message data,
* However msgData here is a byte[] and this can't hold more than 2^32-1
*/
private static BigInteger MAX_MSG_DATA = BigInteger.valueOf(Integer.MAX_VALUE);
/* CALLDATALOAD op */
public DataWord getDataValue(DataWord indexData) {
BigInteger tempIndex = indexData.value();
int index = tempIndex.intValue(); // possible overflow is caught below
int size = 32; // maximum datavalue size
if (msgData == null || index >= msgData.length
|| tempIndex.compareTo(MAX_MSG_DATA) == 1)
return new DataWord();
if (index + size > msgData.length)
size = msgData.length - index;
byte[] data = new byte[32];
System.arraycopy(msgData, index, data, 0, size);
return new DataWord(data);
}
/* CALLDATASIZE */
public DataWord getDataSize() {
if (msgData == null || msgData.length == 0) return DataWord.ZERO;
int size = msgData.length;
return new DataWord(size);
}
/* CALLDATACOPY */
public byte[] getDataCopy(DataWord offsetData, DataWord lengthData) {
int offset = offsetData.intValueSafe();
int length = lengthData.intValueSafe();
byte[] data = new byte[length];
if (msgData == null) return data;
if (offset > msgData.length) return data;
if (offset + length > msgData.length) length = msgData.length - offset;
System.arraycopy(msgData, offset, data, 0, length);
return data;
}
/* PREVHASH op */
public DataWord getPrevHash() {
return prevHash;
}
/* COINBASE op */
public DataWord getCoinbase() {
return coinbase;
}
/* TIMESTAMP op */
public DataWord getTimestamp() {
return timestamp;
}
/* NUMBER op */
public DataWord getNumber() {
return number;
}
/* DIFFICULTY op */
public DataWord getDifficulty() {
return difficulty;
}
/* GASLIMIT op */
public DataWord getGaslimit() {
return gaslimit;
}
/* Storage */
public Map<DataWord, DataWord> getStorage() {
return storage;
}
public Repository getRepository() {
return repository;
}
@Override
public BlockStore getBlockStore() {
return blockStore;
}
@Override
public boolean byTransaction() {
return byTransaction;
}
@Override
public boolean byTestingSuite() {
return byTestingSuite;
}
@Override
public int getCallDeep() {
return this.callDeep;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
ProgramInvokeImpl that = (ProgramInvokeImpl) o;
if (byTestingSuite != that.byTestingSuite) return false;
if (byTransaction != that.byTransaction) return false;
if (address != null ? !address.equals(that.address) : that.address != 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 (caller != null ? !caller.equals(that.caller) : that.caller != null) return false;
if (coinbase != null ? !coinbase.equals(that.coinbase) : that.coinbase != null) return false;
if (difficulty != null ? !difficulty.equals(that.difficulty) : that.difficulty != null) return false;
if (gas != null ? !gas.equals(that.gas) : that.gas != null) return false;
if (gasPrice != null ? !gasPrice.equals(that.gasPrice) : that.gasPrice != null) return false;
if (gaslimit != null ? !gaslimit.equals(that.gaslimit) : that.gaslimit != null) return false;
if (!Arrays.equals(msgData, that.msgData)) 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 (prevHash != null ? !prevHash.equals(that.prevHash) : that.prevHash != null) return false;
if (repository != null ? !repository.equals(that.repository) : that.repository != null) return false;
if (storage != null ? !storage.equals(that.storage) : that.storage != null) return false;
if (timestamp != null ? !timestamp.equals(that.timestamp) : that.timestamp != null) return false;
return true;
}
@Override
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 +
'}';
}
}