/*
* 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;
import org.ethereum.util.ByteArraySet;
import org.ethereum.vm.CallCreate;
import org.ethereum.vm.DataWord;
import org.ethereum.vm.LogInfo;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import static org.apache.commons.collections4.CollectionUtils.isEmpty;
import static org.apache.commons.collections4.CollectionUtils.size;
import static org.ethereum.util.ByteUtil.EMPTY_BYTE_ARRAY;
/**
* @author Roman Mandeleil
* @since 07.06.2014
*/
public class ProgramResult {
private long gasUsed;
private byte[] hReturn = EMPTY_BYTE_ARRAY;
private RuntimeException exception;
private Set<DataWord> deleteAccounts;
private ByteArraySet touchedAccounts = new ByteArraySet();
private List<InternalTransaction> internalTransactions;
private List<LogInfo> logInfoList;
private long futureRefund = 0;
/*
* for testing runs ,
* call/create is not executed
* but dummy recorded
*/
private List<CallCreate> callCreateList;
public void spendGas(long gas) {
gasUsed += gas;
}
public void refundGas(long gas) {
gasUsed -= gas;
}
public void setHReturn(byte[] hReturn) {
this.hReturn = hReturn;
}
public byte[] getHReturn() {
return hReturn;
}
public RuntimeException getException() {
return exception;
}
public long getGasUsed() {
return gasUsed;
}
public void setException(RuntimeException exception) {
this.exception = exception;
}
public Set<DataWord> getDeleteAccounts() {
if (deleteAccounts == null) {
deleteAccounts = new HashSet<>();
}
return deleteAccounts;
}
public void addDeleteAccount(DataWord address) {
getDeleteAccounts().add(address);
}
public void addDeleteAccounts(Set<DataWord> accounts) {
if (!isEmpty(accounts)) {
getDeleteAccounts().addAll(accounts);
}
}
public void addTouchAccount(byte[] addr) {
touchedAccounts.add(addr);
}
public Set<byte[]> getTouchedAccounts() {
return touchedAccounts;
}
public void addTouchAccounts(Set<byte[]> accounts) {
if (!isEmpty(accounts)) {
getTouchedAccounts().addAll(accounts);
}
}
public List<LogInfo> getLogInfoList() {
if (logInfoList == null) {
logInfoList = new ArrayList<>();
}
return logInfoList;
}
public void addLogInfo(LogInfo logInfo) {
getLogInfoList().add(logInfo);
}
public void addLogInfos(List<LogInfo> logInfos) {
if (!isEmpty(logInfos)) {
getLogInfoList().addAll(logInfos);
}
}
public List<CallCreate> getCallCreateList() {
if (callCreateList == null) {
callCreateList = new ArrayList<>();
}
return callCreateList;
}
public void addCallCreate(byte[] data, byte[] destination, byte[] gasLimit, byte[] value) {
getCallCreateList().add(new CallCreate(data, destination, gasLimit, value));
}
public List<InternalTransaction> getInternalTransactions() {
if (internalTransactions == null) {
internalTransactions = new ArrayList<>();
}
return internalTransactions;
}
public InternalTransaction addInternalTransaction(byte[] parentHash, int deep, byte[] nonce, DataWord gasPrice, DataWord gasLimit,
byte[] senderAddress, byte[] receiveAddress, byte[] value, byte[] data, String note) {
InternalTransaction transaction = new InternalTransaction(parentHash, deep, size(internalTransactions), nonce, gasPrice, gasLimit, senderAddress, receiveAddress, value, data, note);
getInternalTransactions().add(transaction);
return transaction;
}
public void addInternalTransactions(List<InternalTransaction> internalTransactions) {
getInternalTransactions().addAll(internalTransactions);
}
public void rejectInternalTransactions() {
for (InternalTransaction internalTx : getInternalTransactions()) {
internalTx.reject();
}
}
public void addFutureRefund(long gasValue) {
futureRefund += gasValue;
}
public long getFutureRefund() {
return futureRefund;
}
public void resetFutureRefund() {
futureRefund = 0;
}
public void merge(ProgramResult another) {
addInternalTransactions(another.getInternalTransactions());
if (another.getException() == null) {
addDeleteAccounts(another.getDeleteAccounts());
addLogInfos(another.getLogInfoList());
addFutureRefund(another.getFutureRefund());
addTouchAccounts(another.getTouchedAccounts());
}
}
public static ProgramResult empty() {
ProgramResult result = new ProgramResult();
result.setHReturn(EMPTY_BYTE_ARRAY);
return result;
}
}