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

Step 11: kernel integration (put / delete split in contract details) #809

Merged
merged 8 commits into from
Feb 6, 2019
81 changes: 17 additions & 64 deletions modAion/src/org/aion/zero/db/AionContractDetailsImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,7 @@
import static org.aion.crypto.HashUtil.h256;

import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
Expand All @@ -19,7 +17,6 @@
import org.aion.mcf.db.AbstractContractDetails;
import org.aion.mcf.ds.XorDataSource;
import org.aion.mcf.trie.SecureTrie;
import org.aion.mcf.vm.types.DataWord;
import org.aion.rlp.RLP;
import org.aion.rlp.RLPElement;
import org.aion.rlp.RLPItem;
Expand Down Expand Up @@ -70,15 +67,25 @@ public AionContractDetailsImpl(byte[] code) throws Exception {
*/
@Override
public void put(ByteArrayWrapper key, ByteArrayWrapper value) {
Objects.requireNonNull(key);
Objects.requireNonNull(value);

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

if (value.isZero()) {
storageTrie.delete(key.getData());
} else {
byte[] data = RLP.encodeElement(value.getData());
storageTrie.update(key.getData(), data);
}
byte[] data = RLP.encodeElement(value.getData());
storageTrie.update(key.getData(), data);

this.setDirty(true);
this.rlpEncoded = null;
}

@Override
public void delete(ByteArrayWrapper key) {
Objects.requireNonNull(key);

storageTrie.delete(key.getData());

this.setDirty(true);
this.rlpEncoded = null;
Expand All @@ -95,7 +102,7 @@ public void put(ByteArrayWrapper key, ByteArrayWrapper value) {
public ByteArrayWrapper get(ByteArrayWrapper key) {
byte[] data = storageTrie.get(key.getData());
return (data == null || data.length == 0)
? DataWord.ZERO.toWrapper()
? null
: new ByteArrayWrapper(RLP.decode2(data).get(0).getRLPData());
}

Expand Down Expand Up @@ -207,60 +214,6 @@ public byte[] getEncoded() {
return rlpEncoded;
}

/**
* Returns a mapping of all the key-value pairs who have keys in the collection keys.
*
* @param keys The keys to query for.
* @return The associated mappings.
*/
@Override
public Map<ByteArrayWrapper, ByteArrayWrapper> getStorage(Collection<ByteArrayWrapper> keys) {
Map<ByteArrayWrapper, ByteArrayWrapper> storage = new HashMap<>();
if (keys == null) {
throw new IllegalArgumentException("Input keys can't be null");
} else {
for (ByteArrayWrapper key : keys) {
ByteArrayWrapper value = get(key);

// we check if the value is not null,
// cause we keep all historical keys
if ((value != null) && (!value.isZero())) {
storage.put(key, value);
}
}
}

return storage;
}

/**
* Sets the storage to contain the specified keys and values. This method creates pairings of
* the keys and values by mapping the i'th key in storageKeys to the i'th value in
* storageValues.
*
* @param storageKeys The keys.
* @param storageValues The values.
*/
@Override
public void setStorage(
List<ByteArrayWrapper> storageKeys, List<ByteArrayWrapper> storageValues) {
for (int i = 0; i < storageKeys.size(); ++i) {
put(storageKeys.get(i), storageValues.get(i));
}
}

/**
* Sets the storage to contain the specified key-value mappings.
*
* @param storage The specified mappings.
*/
@Override
public void setStorage(Map<ByteArrayWrapper, ByteArrayWrapper> storage) {
for (ByteArrayWrapper key : storage.keySet()) {
put(key, storage.get(key));
}
}

/**
* Get the address associated with this AionContractDetailsImpl.
*
Expand Down
36 changes: 16 additions & 20 deletions modAionBase/src/org/aion/base/db/IContractDetails.java
Original file line number Diff line number Diff line change
@@ -1,23 +1,27 @@
package org.aion.base.db;

import java.util.Collection;
import java.util.List;
import java.util.Map;
import org.aion.base.util.ByteArrayWrapper;
import org.aion.vm.api.interfaces.Address;

public interface IContractDetails {

/**
* Inserts key and value as a key-value pair. If the underlying byte array of value consists
* only of zero bytes then ay existing key-value pair that has the same key as key will be
* deleted.
* Inserts a key-value pair containing the given key and the given value.
*
* @param key The key.
* @param value The value.
* @param key the key to be inserted
* @param value the value to be inserted
*/
void put(ByteArrayWrapper key, ByteArrayWrapper value);

/**
* Deletes any key-value pair that matches the given key.
*
* @param key the key to be deleted
*/
void delete(ByteArrayWrapper key);

/**
* Returns the value associated with key.
*
Expand Down Expand Up @@ -113,27 +117,19 @@ public interface IContractDetails {
byte[] getEncoded();

/**
* Returns a mapping of all the key-value pairs who have keys in the collection keys.
* Returns a mapping of all the key-value pairs that have keys in the given collection keys.
*
* @param keys The keys to query for.
* @return The associated mappings.
* @param keys the keys to query for
* @return the associated mappings
*/
Map<ByteArrayWrapper, ByteArrayWrapper> getStorage(Collection<ByteArrayWrapper> keys);

/**
* Sets the storage to contain the specified keys and values. This method creates pairings of
* the keys and values by mapping the i'th key in storageKeys to the i'th value in
* storageValues.
*
* @param storageKeys The keys.
* @param storageValues The values.
*/
void setStorage(List<ByteArrayWrapper> storageKeys, List<ByteArrayWrapper> storageValues);

/**
* Sets the storage to contain the specified key-value mappings.
*
* @param storage The specified mappings.
* @param storage the specified mappings
* @apiNote Used for testing.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I marked the fact that it was only used for testing so that maybe it gets removed from the interface during the refactoring. Then the tag can be added to the implementations.

* @implNote A {@code null} value is interpreted as deletion.
*/
void setStorage(Map<ByteArrayWrapper, ByteArrayWrapper> storage);

Expand Down
10 changes: 9 additions & 1 deletion modAionBase/src/org/aion/base/db/IRepositoryCache.java
Original file line number Diff line number Diff line change
Expand Up @@ -76,10 +76,18 @@ public interface IRepositoryCache<AS, BSB> extends IRepository<AS, BSB> {
* Store the given data at the given key in the account associated with the given address.
*
* @param address the address of the account of interest
* @param key the key at which the date will be stored
* @param key the key at which the data will be stored
* @param value the data to be stored
*/
void addStorageRow(Address address, ByteArrayWrapper key, ByteArrayWrapper value);

/**
* Remove the given storage key from the account associated with the given address.
*
* @param address the address of the account of interest
* @param key the key for which the data will be removed
*/
void removeStorageRow(Address address, ByteArrayWrapper key);

void flushTo(IRepository repo, boolean clearStateAfterFlush);
}
9 changes: 9 additions & 0 deletions modAionBase/src/org/aion/base/util/ByteArrayWrapper.java
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,15 @@ public boolean isZero() {
return true;
}

/**
* Checks if the stored byte array is empty.
*
* @return {@code true} if empty, {@code false} otherwise
*/
public boolean isEmpty() {
return data.length == 0;
}

public ByteArrayWrapper copy() {
int length = data.length;
byte[] bs = new byte[length];
Expand Down
5 changes: 4 additions & 1 deletion modAionImpl/src/org/aion/zero/impl/AionGenesis.java
Original file line number Diff line number Diff line change
Expand Up @@ -349,6 +349,7 @@ protected byte[] generateRootHash() {
AionContractDetailsImpl networkBalanceStorage = new AionContractDetailsImpl();

for (Map.Entry<Integer, BigInteger> entry : this.networkBalance.entrySet()) {
// we assume there are no deletions in the genesis
networkBalanceStorage.put(
new DataWord(entry.getKey()).toWrapper(),
wrapValueForPut(new DataWord(entry.getValue())));
Expand All @@ -370,7 +371,9 @@ protected byte[] generateRootHash() {
}

private static ByteArrayWrapper wrapValueForPut(DataWord value) {
return (value.isZero()) ? DataWord.ZERO.toWrapper() : new ByteArrayWrapper(value.getNoLeadZeroesData());
return (value.isZero())
? DataWord.ZERO.toWrapper()
: new ByteArrayWrapper(value.getNoLeadZeroesData());
}

private static byte[] generateExtraData(int chainId) {
Expand Down
5 changes: 4 additions & 1 deletion modAionImpl/src/org/aion/zero/impl/AionHubUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ public static void buildGenesis(AionGenesis genesis, AionRepositoryImpl reposito
track.createAccount(networkBalanceAddress);

for (Map.Entry<Integer, BigInteger> addr : genesis.getNetworkBalances().entrySet()) {
// assumes only additions are performed in the genesis
track.addStorageRow(
networkBalanceAddress,
new DataWord(addr.getKey()).toWrapper(),
Expand All @@ -37,6 +38,8 @@ public static void buildGenesis(AionGenesis genesis, AionRepositoryImpl reposito
}

private static ByteArrayWrapper wrapValueForPut(DataWord value) {
return (value.isZero()) ? value.toWrapper() : new ByteArrayWrapper(value.getNoLeadZeroesData());
return (value.isZero())
? value.toWrapper()
: new ByteArrayWrapper(value.getNoLeadZeroesData());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -324,6 +324,7 @@ public boolean isAvmEnabled() {
track.createAccount(ContractFactory.getTotalCurrencyContractAddress());

for (Map.Entry<Integer, BigInteger> key : genesis.getNetworkBalances().entrySet()) {
// assumes only additions can be made in the genesis
track.addStorageRow(
ContractFactory.getTotalCurrencyContractAddress(),
new DataWord(key.getKey()).toWrapper(),
Expand Down
35 changes: 22 additions & 13 deletions modAionImpl/src/org/aion/zero/impl/db/AionRepositoryDummy.java
Original file line number Diff line number Diff line change
Expand Up @@ -139,24 +139,33 @@ public BigInteger getBalance(Address addr) {
public ByteArrayWrapper getStorageValue(Address addr, ByteArrayWrapper key) {
IContractDetails details = getContractDetails(addr);
ByteArrayWrapper value = (details == null) ? null : details.get(key);
if (value == null) {
return null;
}
return (value.isZero()) ? null : value;
}

public void addStorageRow(Address addr, ByteArrayWrapper key, ByteArrayWrapper value) {
IContractDetails details = getContractDetails(addr);

if (details == null) {
createAccount(addr);
details = getContractDetails(addr);
if (value != null && value.isZero()) {
// TODO: remove when integrating the AVM
// used to ensure FVM correctness
throw new IllegalStateException(
"The contract address "
+ addr.toString()
+ " returned a zero value for the key "
+ key.toString()
+ " which is not a valid stored value for the FVM. ");
}

details.put(key, value);
detailsDB.put(ByteArrayWrapper.wrap(addr.toBytes()), details);
return value;
}

// never used
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

delete?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We may want to remove the full class, cause there are multiple classes used for repository test functionality. But this feels like a separate task.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If this is the test class that ends up remaining after refactoring, the functionality may be reenabled.

// public void addStorageRow(Address addr, ByteArrayWrapper key, ByteArrayWrapper value) {
// IContractDetails details = getContractDetails(addr);
//
// if (details == null) {
// createAccount(addr);
// details = getContractDetails(addr);
// }
// details.put(key, value);
// detailsDB.put(ByteArrayWrapper.wrap(addr.toBytes()), details);
// }

public byte[] getCode(Address addr) {
IContractDetails details = getContractDetails(addr);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -314,11 +314,7 @@ public BigInteger getBalance(Address address) {
@Override
public ByteArrayWrapper getStorageValue(Address address, ByteArrayWrapper key) {
IContractDetails details = getContractDetails(address);
ByteArrayWrapper value = (details == null) ? null : details.get(key);
if (value == null) {
return null;
}
return (value.isZero()) ? null : value;
return (details == null) ? null : details.get(key);
}

@Override
Expand Down
Loading