Skip to content

Commit

Permalink
separating insert and delete functionality inside the contract details
Browse files Browse the repository at this point in the history
 - this commit currently appears before one that added inplementations
   to new interface methods
  • Loading branch information
AlexandraRoatis committed Jan 23, 2019
1 parent 32e4408 commit 11632c7
Show file tree
Hide file tree
Showing 16 changed files with 279 additions and 225 deletions.
2 changes: 1 addition & 1 deletion aion_fastvm
2 changes: 1 addition & 1 deletion aion_vm_api
93 changes: 26 additions & 67 deletions modAion/src/org/aion/zero/db/AionContractDetailsImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,8 @@
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.Objects;
import org.aion.base.db.IByteArrayKeyValueStore;
import org.aion.base.db.IContractDetails;
import org.aion.base.type.AionAddress;
Expand Down Expand Up @@ -72,18 +70,32 @@ public void put(ByteArrayWrapper key, ByteArrayWrapper value) {
// We strip leading zeros of a DataWord but not a DoubleDataWord so that when we call get
// we can differentiate between the two.

Objects.requireNonNull(key);
Objects.requireNonNull(value);

if (value.isZero()) {
storageTrie.delete(key.getData());
} else {
// TODO: VM must handle padding
boolean isDouble = value.getData().length == DoubleDataWord.BYTES;
byte[] data =
(isDouble)
? RLP.encodeElement(value.getData())
: RLP.encodeElement(value.getNoLeadZeroesData());
storageTrie.update(key.getData(), data);
// TODO: remove when integrating the AVM
// used to ensure FVM correctness
throw new IllegalArgumentException(
"Put with zero values is not allowed for the FVM. Explicit call to delete is necessary.");
}

// TODO: VM must handle padding
boolean isDouble = value.getData().length == DoubleDataWord.BYTES;
byte[] data =
(isDouble)
? RLP.encodeElement(value.getData())
: RLP.encodeElement(value.getNoLeadZeroesData());
storageTrie.update(key.getData(), data);

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

@Override
public void delete(ByteArrayWrapper key) {
storageTrie.delete(key.getData());

this.setDirty(true);
this.rlpEncoded = null;
}
Expand All @@ -97,9 +109,10 @@ public void put(ByteArrayWrapper key, ByteArrayWrapper value) {
*/
@Override
public ByteArrayWrapper get(ByteArrayWrapper key) {
ByteArrayWrapper result = DataWord.ZERO.toWrapper();
ByteArrayWrapper result = null;

byte[] data = storageTrie.get(key.getData());

// TODO: VM must handle padding
if (data.length >= DoubleDataWord.BYTES) {
result = new DoubleDataWord(RLP.decode2(data).get(0).getRLPData()).toWrapper();
Expand Down Expand Up @@ -199,60 +212,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
5 changes: 5 additions & 0 deletions modAion/src/org/aion/zero/db/AionRepositoryCache.java
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,11 @@ public void flush() {
}
}

@Override
public void flushTo(IRepository other, boolean clearStateAfterFlush) {
// TODO: remove this placeholder for changes made in a reorganized commit
}

@Override
public void updateBatch(
Map<Address, AccountState> accounts, final Map<Address, IContractDetails> details) {
Expand Down
29 changes: 18 additions & 11 deletions modAionBase/src/org/aion/base/db/IContractDetails.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,20 @@
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 @@ -103,10 +108,10 @@ 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);

Expand All @@ -115,15 +120,17 @@ public interface IContractDetails {
* 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.
* @implNote A {@code null} value is interpreted as deletion.
* @param storageKeys the list of keys
* @param storageValues the list of values
*/
void setStorage(List<ByteArrayWrapper> storageKeys, List<ByteArrayWrapper> storageValues);

/**
* Sets the storage to contain the specified key-value mappings.
*
* @param storage The specified mappings.
* @implNote A {@code null} value is interpreted as deletion.
* @param storage the specified mappings
*/
void setStorage(Map<ByteArrayWrapper, ByteArrayWrapper> storage);

Expand Down
12 changes: 11 additions & 1 deletion modAionBase/src/org/aion/base/db/IRepositoryCache.java
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +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);
}
11 changes: 7 additions & 4 deletions modAionImpl/src/org/aion/zero/impl/db/AionRepositoryDummy.java
Original file line number Diff line number Diff line change
Expand Up @@ -139,10 +139,14 @@ public BigInteger getBalance(AionAddress addr) {
public ByteArrayWrapper getStorageValue(AionAddress addr, ByteArrayWrapper key) {
IContractDetails details = getContractDetails(addr);
ByteArrayWrapper value = (details == null) ? null : details.get(key);
if (value == null) {
return null;

if (value != null && value.isZero()) {
// TODO: remove when integrating the AVM
// used to ensure FVM correctness
throw new IllegalStateException("Zero values should not be returned by contract.");
}
return (value.isZero()) ? null : value;

return value;
}

public void addStorageRow(AionAddress addr, ByteArrayWrapper key, ByteArrayWrapper value) {
Expand All @@ -152,7 +156,6 @@ public void addStorageRow(AionAddress addr, ByteArrayWrapper key, ByteArrayWrapp
createAccount(addr);
details = getContractDetails(addr);
}

details.put(key, value);
detailsDB.put(addr.toByteArrayWrapper(), details);
}
Expand Down
22 changes: 7 additions & 15 deletions modAionImpl/test/org/aion/db/AionContractDetailsTest.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package org.aion.db;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;

import java.util.HashMap;
Expand Down Expand Up @@ -118,13 +119,11 @@ public void test_2() throws Exception {
byte[] val_1 = ByteUtil.hexStringToBytes("0000000000000000000000000000000c");

byte[] key_2 = ByteUtil.hexStringToBytes("5a448d1967513482947d1d3f6104316f");
byte[] val_2 = ByteUtil.hexStringToBytes("00000000000000000000000000000000");

byte[] key_3 = ByteUtil.hexStringToBytes("5a448d1967513482947d1d3f61043171");
byte[] val_3 = ByteUtil.hexStringToBytes("00000000000000000000000000000014");

byte[] key_4 = ByteUtil.hexStringToBytes("18d63b70aa690ad37cb50908746c9a54");
byte[] val_4 = ByteUtil.hexStringToBytes("00000000000000000000000000000000");

byte[] key_5 = ByteUtil.hexStringToBytes("5a448d1967513482947d1d3f61043170");
byte[] val_5 = ByteUtil.hexStringToBytes("00000000000000000000000000000078");
Expand Down Expand Up @@ -158,9 +157,9 @@ public void test_2() throws Exception {
contractDetails.setAddress(address);
contractDetails.put(new DataWord(key_0).toWrapper(), new DataWord(val_0).toWrapper());
contractDetails.put(new DataWord(key_1).toWrapper(), new DataWord(val_1).toWrapper());
contractDetails.put(new DataWord(key_2).toWrapper(), new DataWord(val_2).toWrapper());
contractDetails.delete(new DataWord(key_2).toWrapper());
contractDetails.put(new DataWord(key_3).toWrapper(), new DataWord(val_3).toWrapper());
contractDetails.put(new DataWord(key_4).toWrapper(), new DataWord(val_4).toWrapper());
contractDetails.delete(new DataWord(key_4).toWrapper());
contractDetails.put(new DataWord(key_5).toWrapper(), new DataWord(val_5).toWrapper());
contractDetails.put(new DataWord(key_6).toWrapper(), new DataWord(val_6).toWrapper());
contractDetails.put(new DataWord(key_7).toWrapper(), new DataWord(val_7).toWrapper());
Expand All @@ -184,20 +183,14 @@ public void test_2() throws Exception {
ByteUtil.toHexString(
contractDetails_.get(new DataWord(key_1).toWrapper()).getData()));

assertEquals(
ByteUtil.toHexString(val_2),
ByteUtil.toHexString(
contractDetails_.get(new DataWord(key_2).toWrapper()).getData()));
assertNull(contractDetails_.get(new DataWord(key_2).toWrapper()));

assertEquals(
ByteUtil.toHexString(val_3),
ByteUtil.toHexString(
contractDetails_.get(new DataWord(key_3).toWrapper()).getData()));

assertEquals(
ByteUtil.toHexString(val_4),
ByteUtil.toHexString(
contractDetails_.get(new DataWord(key_4).toWrapper()).getData()));
assertNull(contractDetails_.get(new DataWord(key_4).toWrapper()));

assertEquals(
ByteUtil.toHexString(val_5),
Expand Down Expand Up @@ -287,9 +280,8 @@ public void testExternalStorageSerialization() {

DataWord deletedKey = elements.keySet().iterator().next();

deserialized.put(deletedKey.toWrapper(), DataWord.ZERO.toWrapper());
deserialized.put(
new DataWord(RandomUtils.nextBytes(16)).toWrapper(), DataWord.ZERO.toWrapper());
deserialized.delete(deletedKey.toWrapper());
deserialized.delete(new DataWord(RandomUtils.nextBytes(16)).toWrapper());
}

@Test
Expand Down
61 changes: 61 additions & 0 deletions modMcf/src/org/aion/mcf/db/AbstractContractDetails.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@
import static org.aion.crypto.HashUtil.h256;
import static org.aion.util.bytes.ByteUtil.EMPTY_BYTE_ARRAY;

import com.google.common.annotations.VisibleForTesting;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.aion.base.db.IContractDetails;
import org.aion.base.util.ByteArrayWrapper;
Expand Down Expand Up @@ -101,4 +104,62 @@ public String toString() {
ret += " Storage: " + getStorageHash();
return ret;
}

@VisibleForTesting
@Override
public void setStorage(
List<ByteArrayWrapper> storageKeys, List<ByteArrayWrapper> storageValues) {
for (int i = 0; i < storageKeys.size(); ++i) {
ByteArrayWrapper key = storageKeys.get(i);
ByteArrayWrapper value = storageValues.get(i);

if (value != null) {
put(key, value);
} else {
delete(key);
}
}
}

@VisibleForTesting
@Override
public void setStorage(Map<ByteArrayWrapper, ByteArrayWrapper> storage) {
for (Map.Entry<ByteArrayWrapper, ByteArrayWrapper> entry : storage.entrySet()) {
ByteArrayWrapper key = entry.getKey();
ByteArrayWrapper value = entry.getValue();

if (value != null) {
put(key, value);
} else {
delete(key);
}
}
}

@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) {
if (value.isZero()) {
// TODO: remove when integrating the AVM
// used to ensure FVM correctness
throw new IllegalArgumentException(
"Put with zero values is not allowed for the FVM. Explicit call to delete is necessary.");
}
storage.put(key, value);
}
}
}

return storage;
}
}
Loading

0 comments on commit 11632c7

Please sign in to comment.