/*
* 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.Block;
import org.ethereum.core.Blockchain;
import org.ethereum.core.Repository;
import org.ethereum.core.Transaction;
import org.ethereum.db.BlockStore;
import org.ethereum.util.ByteUtil;
import org.ethereum.vm.DataWord;
import org.ethereum.vm.program.Program;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.spongycastle.util.encoders.Hex;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.math.BigInteger;
import static org.apache.commons.lang3.ArrayUtils.nullToEmpty;
/**
* @author Roman Mandeleil
* @since 08.06.2014
*/
@Component("ProgramInvokeFactory")
public class ProgramInvokeFactoryImpl implements ProgramInvokeFactory {
private static final Logger logger = LoggerFactory.getLogger("VM");
// Invocation by the wire tx
@Override
public ProgramInvoke createProgramInvoke(Transaction tx, Block block, Repository repository,
BlockStore blockStore) {
/*** ADDRESS op ***/
// YP: Get address of currently executing account.
byte[] address = tx.isContractCreation() ? tx.getContractAddress() : tx.getReceiveAddress();
/*** ORIGIN op ***/
// YP: This is the sender of original transaction; it is never a contract.
byte[] origin = tx.getSender();
/*** CALLER op ***/
// YP: This is the address of the account that is directly responsible for this execution.
byte[] caller = tx.getSender();
/*** BALANCE op ***/
byte[] balance = repository.getBalance(address).toByteArray();
/*** GASPRICE op ***/
byte[] gasPrice = tx.getGasPrice();
/*** GAS op ***/
byte[] gas = tx.getGasLimit();
/*** CALLVALUE op ***/
byte[] callValue = nullToEmpty(tx.getValue());
/*** CALLDATALOAD op ***/
/*** CALLDATACOPY op ***/
/*** CALLDATASIZE op ***/
byte[] data = tx.isContractCreation() ? ByteUtil.EMPTY_BYTE_ARRAY : nullToEmpty(tx.getData());
/*** PREVHASH op ***/
byte[] lastHash = block.getParentHash();
/*** COINBASE op ***/
byte[] coinbase = block.getCoinbase();
/*** TIMESTAMP op ***/
long timestamp = block.getTimestamp();
/*** NUMBER op ***/
long number = block.getNumber();
/*** DIFFICULTY op ***/
byte[] difficulty = block.getDifficulty();
/*** GASLIMIT op ***/
byte[] gaslimit = block.getGasLimit();
if (logger.isInfoEnabled()) {
logger.info("Top level call: \n" +
"address={}\n" +
"origin={}\n" +
"caller={}\n" +
"balance={}\n" +
"gasPrice={}\n" +
"gas={}\n" +
"callValue={}\n" +
"data={}\n" +
"lastHash={}\n" +
"coinbase={}\n" +
"timestamp={}\n" +
"blockNumber={}\n" +
"difficulty={}\n" +
"gaslimit={}\n",
Hex.toHexString(address),
Hex.toHexString(origin),
Hex.toHexString(caller),
ByteUtil.bytesToBigInteger(balance),
ByteUtil.bytesToBigInteger(gasPrice),
ByteUtil.bytesToBigInteger(gas),
ByteUtil.bytesToBigInteger(callValue),
Hex.toHexString(data),
Hex.toHexString(lastHash),
Hex.toHexString(coinbase),
timestamp,
number,
Hex.toHexString(difficulty),
gaslimit);
}
return new ProgramInvokeImpl(address, origin, caller, balance, gasPrice, gas, callValue, data,
lastHash, coinbase, timestamp, number, difficulty, gaslimit,
repository, blockStore);
}
/**
* This invocation created for contract call contract
*/
@Override
public ProgramInvoke createProgramInvoke(Program program, DataWord toAddress, DataWord callerAddress,
DataWord inValue, DataWord inGas,
BigInteger balanceInt, byte[] dataIn,
Repository repository, BlockStore blockStore, boolean byTestingSuite) {
DataWord address = toAddress;
DataWord origin = program.getOriginAddress();
DataWord caller = callerAddress;
DataWord balance = new DataWord(balanceInt.toByteArray());
DataWord gasPrice = program.getGasPrice();
DataWord gas = inGas;
DataWord callValue = inValue;
byte[] data = dataIn;
DataWord lastHash = program.getPrevHash();
DataWord coinbase = program.getCoinbase();
DataWord timestamp = program.getTimestamp();
DataWord number = program.getNumber();
DataWord difficulty = program.getDifficulty();
DataWord gasLimit = program.getGasLimit();
if (logger.isInfoEnabled()) {
logger.info("Internal call: \n" +
"address={}\n" +
"origin={}\n" +
"caller={}\n" +
"balance={}\n" +
"gasPrice={}\n" +
"gas={}\n" +
"callValue={}\n" +
"data={}\n" +
"lastHash={}\n" +
"coinbase={}\n" +
"timestamp={}\n" +
"blockNumber={}\n" +
"difficulty={}\n" +
"gaslimit={}\n",
Hex.toHexString(address.getLast20Bytes()),
Hex.toHexString(origin.getLast20Bytes()),
Hex.toHexString(caller.getLast20Bytes()),
balance.toString(),
gasPrice.longValue(),
gas.longValue(),
Hex.toHexString(callValue.getNoLeadZeroesData()),
data == null ? "" : Hex.toHexString(data),
Hex.toHexString(lastHash.getData()),
Hex.toHexString(coinbase.getLast20Bytes()),
timestamp.longValue(),
number.longValue(),
Hex.toHexString(difficulty.getNoLeadZeroesData()),
gasLimit.bigIntValue());
}
return new ProgramInvokeImpl(address, origin, caller, balance, gasPrice, gas, callValue,
data, lastHash, coinbase, timestamp, number, difficulty, gasLimit,
repository, program.getCallDeep() + 1, blockStore, byTestingSuite);
}
}