/*
* 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.jsontestsuite.suite;
import org.ethereum.db.ContractDetails;
import org.ethereum.trie.SecureTrie;
import org.ethereum.util.RLP;
import org.ethereum.vm.DataWord;
import java.util.*;
import static java.util.Collections.unmodifiableMap;
/**
* @author Roman Mandeleil
* @since 24.06.2014
*/
public class ContractDetailsCacheImpl extends AbstractContractDetails {
private Map<DataWord, DataWord> storage = new HashMap<>();
ContractDetails origContract;
public ContractDetailsCacheImpl(ContractDetails origContract) {
this.origContract = origContract;
if (origContract != null) {
if (origContract instanceof AbstractContractDetails) {
setCodes(((AbstractContractDetails) this.origContract).getCodes());
} else {
setCode(origContract.getCode());
}
}
}
@Override
public void put(DataWord key, DataWord value) {
storage.put(key, value);
this.setDirty(true);
}
@Override
public DataWord get(DataWord key) {
DataWord value = storage.get(key);
if (value != null)
value = value.clone();
else{
if (origContract == null) return null;
value = origContract.get(key);
storage.put(key.clone(), value == null ? DataWord.ZERO.clone() : value.clone());
}
if (value == null || value.isZero())
return null;
else
return value;
}
@Override
public byte[] getStorageHash() { // todo: unsupported
SecureTrie storageTrie = new SecureTrie((byte[]) null);
for (DataWord key : storage.keySet()) {
DataWord value = storage.get(key);
storageTrie.put(key.getData(),
RLP.encodeElement(value.getNoLeadZeroesData()));
}
return storageTrie.getRootHash();
}
@Override
public void decode(byte[] rlpCode) {
throw new RuntimeException("Not supported by this implementation.");
}
@Override
public byte[] getEncoded() {
throw new RuntimeException("Not supported by this implementation.");
}
@Override
public Map<DataWord, DataWord> getStorage() {
return unmodifiableMap(storage);
}
@Override
public Map<DataWord, DataWord> getStorage(Collection<DataWord> keys) {
if (keys == null) return getStorage();
Map<DataWord, DataWord> result = new HashMap<>();
for (DataWord key : keys) {
result.put(key, storage.get(key));
}
return unmodifiableMap(result);
}
@Override
public int getStorageSize() {
return (origContract == null)
? storage.size()
: origContract.getStorageSize();
}
@Override
public Set<DataWord> getStorageKeys() {
return (origContract == null)
? storage.keySet()
: origContract.getStorageKeys();
}
@Override
public void setStorage(List<DataWord> storageKeys, List<DataWord> storageValues) {
for (int i = 0; i < storageKeys.size(); ++i){
DataWord key = storageKeys.get(i);
DataWord value = storageValues.get(i);
if (value.isZero())
storage.put(key, null);
}
}
@Override
public void setStorage(Map<DataWord, DataWord> storage) {
this.storage = storage;
}
@Override
public byte[] getAddress() {
return (origContract == null) ? null : origContract.getAddress();
}
@Override
public void setAddress(byte[] address) {
if (origContract != null) origContract.setAddress(address);
}
@Override
public ContractDetails clone() {
ContractDetailsCacheImpl contractDetails = new ContractDetailsCacheImpl(origContract);
Object storageClone = ((HashMap<DataWord, DataWord>)storage).clone();
contractDetails.setCode(this.getCode());
contractDetails.setStorage( (HashMap<DataWord, DataWord>) storageClone);
return contractDetails;
}
@Override
public void syncStorage() {
if (origContract != null) origContract.syncStorage();
}
public void commit(){
if (origContract == null) return;
for (DataWord key : storage.keySet()) {
origContract.put(key, storage.get(key));
}
if (origContract instanceof AbstractContractDetails) {
((AbstractContractDetails) origContract).appendCodes(getCodes());
} else {
origContract.setCode(getCode());
}
origContract.setDirty(this.isDirty() || origContract.isDirty());
}
@Override
public ContractDetails getSnapshotTo(byte[] hash) {
throw new UnsupportedOperationException("No snapshot option during cache state");
}
}