Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FVM contract encoding update #867

Merged
merged 5 commits into from
Apr 5, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions modAionImpl/src/org/aion/zero/impl/AionBlockchainImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,12 @@
import org.aion.mcf.trie.Trie;
import org.aion.mcf.trie.TrieImpl;
import org.aion.mcf.trie.TrieNodeResult;
import org.aion.mcf.tx.TransactionTypes;
import org.aion.mcf.types.BlockIdentifierImpl;
import org.aion.mcf.valid.BlockHeaderValidator;
import org.aion.mcf.valid.GrandParentBlockHeaderValidator;
import org.aion.mcf.valid.ParentBlockHeaderValidator;
import org.aion.mcf.valid.TransactionTypeRule;
import org.aion.mcf.vm.types.Bloom;
import org.aion.rlp.RLP;
import org.aion.types.Address;
Expand Down Expand Up @@ -75,9 +77,7 @@
import org.aion.zero.impl.types.AionTxInfo;
import org.aion.zero.impl.types.RetValidPreBlock;
import org.aion.zero.impl.valid.TXValidator;
import org.aion.mcf.valid.TransactionTypeRule;
import org.aion.zero.impl.valid.TransactionTypeValidator;
import org.aion.mcf.tx.TransactionTypes;
import org.aion.zero.types.A0BlockHeader;
import org.aion.zero.types.AionTransaction;
import org.aion.zero.types.AionTxExecSummary;
Expand Down Expand Up @@ -1008,10 +1008,10 @@ public AionBlockSummary add(AionBlock block, boolean rebuild) {
// update corresponding account with the new balance
track.flush();

// save contract creation data
// save contract creation data to index database
for (AionTxReceipt receipt : receipts) {
AionTransaction tx = receipt.getTransaction();
if (tx.isContractCreationTransaction()) {
if (tx.isContractCreationTransaction() && receipt.isSuccessful()) {
repository.saveIndexedContractInformation(
tx.getContractAddress(),
block.getNumber(),
Expand Down
2 changes: 2 additions & 0 deletions modAionImpl/src/org/aion/zero/impl/cli/Cli.java
Original file line number Diff line number Diff line change
Expand Up @@ -522,7 +522,9 @@ public ReturnType call(final String[] args, Cfg cfg) {
String parameter = options.isRedoImport();

if (parameter.isEmpty()) {
VirtualMachineProvider.initializeAllVirtualMachines();
RecoveryUtils.redoMainChainImport(height);
VirtualMachineProvider.shutdownAllVirtualMachines();
return EXIT;
} else {
try {
Expand Down
11 changes: 11 additions & 0 deletions modAionImpl/src/org/aion/zero/impl/db/AbstractContractDetails.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import java.util.HashMap;
import java.util.Map;
import org.aion.interfaces.db.ContractDetails;
import org.aion.mcf.tx.TransactionTypes;
import org.aion.types.ByteArrayWrapper;
import org.aion.util.conversions.Hex;

Expand All @@ -22,6 +23,8 @@ public abstract class AbstractContractDetails implements ContractDetails {
protected int detailsInMemoryStorageLimit;

private Map<ByteArrayWrapper, byte[]> codes = new HashMap<>();
// set to FVM_CREATE_CODE to update encoding for FVM contracts
protected byte vmType = TransactionTypes.FVM_CREATE_CODE;

protected AbstractContractDetails() {
this(0, 64 * 1024);
Expand Down Expand Up @@ -72,6 +75,14 @@ public void appendCodes(Map<ByteArrayWrapper, byte[]> codes) {
this.codes.putAll(codes);
}

public void setVmType(byte vmType) {
this.vmType = vmType;
}

public byte getVmType() {
return vmType;
}

@Override
public void setDirty(boolean dirty) {
this.dirty = dirty;
Expand Down
85 changes: 75 additions & 10 deletions modAionImpl/src/org/aion/zero/impl/db/AionContractDetailsImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,22 @@
import static org.aion.types.ByteArrayWrapper.wrap;
import static org.aion.util.bytes.ByteUtil.EMPTY_BYTE_ARRAY;

import com.google.common.annotations.VisibleForTesting;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
import org.aion.interfaces.db.ByteArrayKeyValueStore;
import org.aion.interfaces.db.ContractDetails;
import org.aion.types.Address;
import org.aion.mcf.ds.XorDataSource;
import org.aion.mcf.trie.SecureTrie;
import org.aion.mcf.tx.TransactionTypes;
import org.aion.rlp.RLP;
import org.aion.rlp.RLPElement;
import org.aion.rlp.RLPItem;
import org.aion.rlp.RLPList;
import org.aion.types.Address;
import org.aion.types.ByteArrayWrapper;

public class AionContractDetailsImpl extends AbstractContractDetails {
Expand Down Expand Up @@ -73,8 +75,8 @@ public void put(ByteArrayWrapper key, ByteArrayWrapper value) {
Objects.requireNonNull(value);

// The following must be done before making this call:
// We strip leading zeros of a DataWordImpl but not a DoubleDataWord so that when we call get
// we can differentiate between the two.
// We strip leading zeros of a DataWordImpl but not a DoubleDataWord so that when we call
// get we can differentiate between the two.

byte[] data = RLP.encodeElement(value.getData());
storageTrie.update(key.getData(), data);
Expand All @@ -94,8 +96,8 @@ public void delete(ByteArrayWrapper key) {
}

/**
* Returns the value associated with key if it exists, otherwise returns a DataWordImpl consisting
* entirely of zero bytes.
* Returns the value associated with key if it exists, otherwise returns a DataWordImpl
* consisting entirely of zero bytes.
*
* @param key The key to query.
* @return the corresponding value or a zero-byte DataWordImpl if no such value.
Expand All @@ -108,6 +110,10 @@ public ByteArrayWrapper get(ByteArrayWrapper key) {
: new ByteArrayWrapper(RLP.decode2(data).get(0).getRLPData());
}

public byte getVmType() {
return vmType;
}

/**
* Returns the storage hash.
*
Expand Down Expand Up @@ -138,8 +144,41 @@ public void decode(byte[] rlpCode) {
@Override
public void decode(byte[] rlpCode, boolean fastCheck) {
RLPList data = RLP.decode2(rlpCode);

RLPList rlpList = (RLPList) data.get(0);

// compatible with old encoding
decodeEncodingWithoutVmType(rlpList, fastCheck);

if (rlpList.size() == 5) {
// only FVM contracts used the old encoding
vmType = TransactionTypes.FVM_CREATE_CODE;

// save with new encoding
this.rlpEncoded = null;
getEncoded();
} else {
// Decodes the new version of encoding which is a list of 6 elements, specifically:<br>
// { 0:address, 1:isExternalStorage, 2:storageRoot, 3:storage, 4:code, 5: vmType }
RLPItem vm = (RLPItem) rlpList.get(5);

if (vm == null || vm.getRLPData() == null || vm.getRLPData().length == 0) {
throw new IllegalArgumentException("rlp decode error: invalid vm code");
} else {
this.vmType = vm.getRLPData()[0];
}

this.rlpEncoded = rlpCode;
}
}

/**
* Decodes the old version of encoding which was a list of 5 elements, specifically:<br>
* { 0:address, 1:isExternalStorage, 2:storageRoot, 3:storage, 4:code }
*
* <p>Only FVM contracts used this encoding on the <b>mainnet</b> and <b>mastery</b> networks.
*/
public void decodeEncodingWithoutVmType(RLPList rlpList, boolean fastCheck) {
RLPItem isExternalStorage = (RLPItem) rlpList.get(1);
RLPItem storage = (RLPItem) rlpList.get(3);
this.externalStorage = isExternalStorage.getRLPData().length > 0;
Expand All @@ -154,7 +193,9 @@ public void decode(byte[] rlpCode, boolean fastCheck) {
RLPItem storageRoot = (RLPItem) rlpList.get(2);
RLPElement code = rlpList.get(4);

if (address == null || address.getRLPData() == null || address.getRLPData().length != Address.SIZE) {
if (address == null
|| address.getRLPData() == null
|| address.getRLPData().length != Address.SIZE) {
throw new IllegalArgumentException("rlp decode error.");
} else {
this.address = Address.wrap(address.getRLPData());
Expand All @@ -181,13 +222,14 @@ public void decode(byte[] rlpCode, boolean fastCheck) {
externalStorage = true;
storageTrie.getCache().setDB(getExternalStorageDataSource());
}

this.rlpEncoded = rlpCode;
}

/**
* Returns an rlp encoding of this AionContractDetailsImpl object.
*
* <p>The encoding is a list of 6 elements:<br>
* { 0:address, 1:isExternalStorage, 2:storageRoot, 3:storage, 4:code, 5: vmType }
*
* @return an rlp encoding of this.
*/
@Override
Expand All @@ -208,9 +250,17 @@ public byte[] getEncoded() {
}
byte[] rlpCode = RLP.encodeList(codes);

// vm type was not added
byte[] rlpVmType = RLP.encodeByte(vmType);

this.rlpEncoded =
RLP.encodeList(
rlpAddress, rlpIsExternalStorage, rlpStorageRoot, rlpStorage, rlpCode);
rlpAddress,
rlpIsExternalStorage,
rlpStorageRoot,
rlpStorage,
rlpCode,
rlpVmType);
}

return rlpEncoded;
Expand Down Expand Up @@ -275,8 +325,12 @@ private ByteArrayKeyValueStore getExternalStorageDataSource() {
* Sets the external storage data source to dataSource.
*
* @param dataSource The new data source.
* @implNote The tests are taking a shortcut here in bypassing the XorDataSource created by
* {@link #getExternalStorageDataSource()}. Do not use this method in production.
*/
public void setExternalStorageDataSource(ByteArrayKeyValueStore dataSource) {
@VisibleForTesting
void setExternalStorageDataSource(ByteArrayKeyValueStore dataSource) {
// TODO: regarding the node above: the tests should be updated and the method removed
this.externalStorageDataSource = dataSource;
this.externalStorage = true;
this.storageTrie = new SecureTrie(getExternalStorageDataSource());
Expand All @@ -300,6 +354,11 @@ public ContractDetails getSnapshotTo(byte[] hash) {

AionContractDetailsImpl details =
new AionContractDetailsImpl(this.address, snapStorage, getCodes());

// vm information
details.vmType = this.vmType;

// storage information
details.externalStorage = this.externalStorage;
details.externalStorageDataSource = this.externalStorageDataSource;
details.dataSource = dataSource;
Expand All @@ -324,9 +383,15 @@ public ContractDetails getSnapshotTo(byte[] hash) {
@Override
public AionContractDetailsImpl copy() {
AionContractDetailsImpl aionContractDetailsCopy = new AionContractDetailsImpl();

// vm information
aionContractDetailsCopy.vmType = this.vmType;

// storage information
aionContractDetailsCopy.dataSource = this.dataSource;
aionContractDetailsCopy.externalStorageDataSource = this.externalStorageDataSource;
aionContractDetailsCopy.externalStorage = this.externalStorage;

aionContractDetailsCopy.prune = this.prune;
aionContractDetailsCopy.detailsInMemoryStorageLimit = this.detailsInMemoryStorageLimit;
aionContractDetailsCopy.setCodes(getDeepCopyOfCodes());
Expand Down
13 changes: 12 additions & 1 deletion modAionImpl/src/org/aion/zero/impl/db/AionRepositoryImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import org.aion.mcf.trie.Trie;
import org.aion.mcf.trie.TrieImpl;
import org.aion.mcf.trie.TrieNodeResult;
import org.aion.mcf.tx.TransactionTypes;
import org.aion.p2p.V1Constants;
import org.aion.types.Address;
import org.aion.types.ByteArrayWrapper;
Expand All @@ -35,7 +36,6 @@
import org.aion.zero.impl.sync.DatabaseType;
import org.aion.zero.impl.types.AionBlock;
import org.aion.zero.impl.types.AionTxInfo;
import org.aion.mcf.tx.TransactionTypes;
import org.aion.zero.types.A0BlockHeader;
import org.aion.zero.types.AionTransaction;
import org.aion.zero.types.AionTxReceipt;
Expand Down Expand Up @@ -648,6 +648,17 @@ public void close() {
LOGGEN.error("Exception occurred while closing the details data source.", e);
}

try {
if (contractIndexDatabase != null) {
contractIndexDatabase.close();
LOGGEN.info("contractIndexDatabase store closed.");
contractIndexDatabase = null;
}
} catch (Exception e) {
LOGGEN.error(
"Exception occurred while closing the pendingTxCacheDatabase store.", e);
}

try {
if (stateDatabase != null) {
stateDatabase.close();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import java.util.Objects;
import org.aion.interfaces.db.ByteArrayKeyValueStore;
import org.aion.interfaces.db.ContractDetails;
import org.aion.mcf.tx.TransactionTypes;
import org.aion.types.Address;
import org.aion.types.ByteArrayWrapper;

Expand All @@ -31,6 +32,7 @@ public ContractDetailsCacheImpl(ContractDetails origContract) {
public static ContractDetailsCacheImpl copy(ContractDetailsCacheImpl cache) {
ContractDetailsCacheImpl copy = new ContractDetailsCacheImpl(cache.origContract);
copy.setCodes(new HashMap<>(cache.getCodes()));
copy.vmType = cache.vmType;
copy.storage = new HashMap<>(cache.storage);
copy.setDirty(cache.isDirty());
copy.setDeleted(cache.isDeleted());
Expand Down Expand Up @@ -96,6 +98,13 @@ public ByteArrayWrapper get(ByteArrayWrapper key) {
return value;
}

public byte getVmType() {
if (vmType == TransactionTypes.DEFAULT && origContract != null) {
vmType = ((AbstractContractDetails) origContract).getVmType();
}
return vmType;
}

/**
* Returns the storage hash.
*
Expand Down Expand Up @@ -222,15 +231,15 @@ public ContractDetailsCacheImpl copy() {

ContractDetails originalContractCopy =
(this.origContract == null) ? null : this.origContract.copy();
ContractDetailsCacheImpl contractDetailsCacheCopy =
new ContractDetailsCacheImpl(originalContractCopy);
contractDetailsCacheCopy.storage = getDeepCopyOfStorage();
contractDetailsCacheCopy.prune = this.prune;
contractDetailsCacheCopy.detailsInMemoryStorageLimit = this.detailsInMemoryStorageLimit;
contractDetailsCacheCopy.setCodes(getDeepCopyOfCodes());
contractDetailsCacheCopy.setDirty(this.isDirty());
contractDetailsCacheCopy.setDeleted(this.isDeleted());
return contractDetailsCacheCopy;
ContractDetailsCacheImpl copy = new ContractDetailsCacheImpl(originalContractCopy);
copy.vmType = this.vmType;
copy.storage = getDeepCopyOfStorage();
copy.prune = this.prune;
copy.detailsInMemoryStorageLimit = this.detailsInMemoryStorageLimit;
copy.setCodes(getDeepCopyOfCodes());
copy.setDirty(this.isDirty());
copy.setDeleted(this.isDeleted());
return copy;
}

private Map<ByteArrayWrapper, byte[]> getDeepCopyOfCodes() {
Expand Down
Loading