use of org.aion.zero.impl.trie.SecureTrie in project aion by aionnetwork.
the class FvmContractDetailsTest method testDecode_withInLineStorageAndTransition.
@Test
public void testDecode_withInLineStorageAndTransition() {
SecureTrie trie = new SecureTrie(null);
Map<ByteArrayWrapper, ByteArrayWrapper> storage = new HashMap<>();
for (int i = 0; i < 3; i++) {
byte[] key = RandomUtils.nextBytes(32);
byte[] value = RandomUtils.nextBytes(100);
trie.update(key, RLP.encodeElement(value));
storage.put(ByteArrayWrapper.wrap(key), ByteArrayWrapper.wrap(value));
}
RLPElement storageTrie = RLP.decode2SharedList(trie.serialize());
AionAddress address = new AionAddress(RandomUtils.nextBytes(AionAddress.LENGTH));
byte[] codeBytes = RandomUtils.nextBytes(100);
RLPElement code = mock(SharedRLPItem.class);
when(code.getRLPData()).thenReturn(codeBytes);
byte[] rootHash = RandomUtils.nextBytes(32);
RLPElement root = mock(SharedRLPItem.class);
when(root.getRLPData()).thenReturn(rootHash);
Logger log = mock(Logger.class);
ByteArrayKeyValueDatabase db = new MockDB("db", log);
db.open();
assertThat(db.isEmpty()).isTrue();
RLPContractDetails input = new RLPContractDetails(address, false, root, storageTrie, code);
FvmContractDetails details = FvmContractDetails.decodeAtRoot(input, db, rootHash);
assertThat(details.address).isEqualTo(address);
// because it uses the setCodes method
assertThat(details.isDirty()).isTrue();
assertThat(details.isDeleted()).isFalse();
assertThat(details.getCodes().size()).isEqualTo(1);
assertThat(details.getCodes().values()).contains(ByteArrayWrapper.wrap(codeBytes));
assertThat(details.getCode(h256(codeBytes))).isEqualTo(codeBytes);
byte[] storageHash = trie.getRootHash();
assertThat(details.getStorageHash()).isEqualTo(storageHash);
for (ByteArrayWrapper key : storage.keySet()) {
assertThat(details.get(key)).isEqualTo(storage.get(key));
}
assertThat(db.isEmpty()).isFalse();
}
use of org.aion.zero.impl.trie.SecureTrie in project aion by aionnetwork.
the class FvmContractDetailsTest method testDecode_withInLineStorageAndEmptyStorageTrie.
@Test
public void testDecode_withInLineStorageAndEmptyStorageTrie() {
SecureTrie trie = new SecureTrie(null);
RLPElement storageTrie = RLP.decode2SharedList(trie.serialize());
AionAddress address = new AionAddress(RandomUtils.nextBytes(AionAddress.LENGTH));
byte[] codeBytes = RandomUtils.nextBytes(100);
RLPElement code = mock(SharedRLPItem.class);
when(code.getRLPData()).thenReturn(codeBytes);
byte[] storageHash = EMPTY_TRIE_HASH;
RLPElement root = mock(SharedRLPItem.class);
when(root.getRLPData()).thenReturn(storageHash);
ByteArrayKeyValueDatabase db = new MockDB("db", log);
db.open();
assertThat(db.isEmpty()).isTrue();
RLPContractDetails input = new RLPContractDetails(address, false, root, storageTrie, code);
FvmContractDetails details = FvmContractDetails.decodeAtRoot(input, db, storageHash);
assertThat(details.address).isEqualTo(address);
// because it uses the setCodes method
assertThat(details.isDirty()).isTrue();
assertThat(details.isDeleted()).isFalse();
assertThat(details.getCodes().size()).isEqualTo(1);
assertThat(details.getCodes().values()).contains(ByteArrayWrapper.wrap(codeBytes));
assertThat(details.getCode(h256(codeBytes))).isEqualTo(codeBytes);
assertThat(details.getStorageHash()).isEqualTo(storageHash);
}
use of org.aion.zero.impl.trie.SecureTrie in project aion by aionnetwork.
the class AvmContractDetails method decodeAtRoot.
/**
* Decodes an AvmContractDetails object from the RLP encoding and returns a snapshot to the
* specific point in the blockchain history given by the consensus root hash.
*
* @param input the stored encoding representing the contract details
* @param storageSource the data source for the contract storage data
* @param objectGraphSource the data source for the object graph
* @param consensusRoot the consensus root linking to specific external storage and object graph
* data at the point of interest in the blockchain history
* @return a snapshot of the contract details with the information it contained at the specified
* point in the blockchain history
*/
public static AvmContractDetails decodeAtRoot(RLPContractDetails input, ByteArrayKeyValueStore storageSource, ByteArrayKeyValueStore objectGraphSource, byte[] consensusRoot) {
Objects.requireNonNull(input, "The contract data for the snapshot cannot be null.");
Objects.requireNonNull(consensusRoot, "The consensus root for the snapshot cannot be null.");
// additional null check are performed by the constructor
AvmContractDetails details = new AvmContractDetails(input.address, storageSource, objectGraphSource);
RLPElement code = input.code;
if (code instanceof SharedRLPList) {
for (RLPElement e : ((SharedRLPList) code)) {
if (e.isList()) {
details.setCode(SharedRLPList.getRLPDataCopy((SharedRLPList) e));
} else {
details.setCode(e.getRLPData());
}
}
} else if (code instanceof RLPList) {
for (RLPElement e : ((RLPList) code)) {
details.setCode(e.getRLPData());
}
} else {
details.setCode(code.getRLPData());
}
// The root is the concatenated storage hash.
// It points to the external storage hash and the object graph hash.
RLPElement storage = input.storageTrie;
// Instantiates the storage interpreting the storage root according to the VM specification.
byte[] storageRootHash;
Optional<byte[]> concatenatedData = details.objectGraphSource.get(consensusRoot);
if (concatenatedData.isPresent()) {
SharedRLPList data = RLP.decode2SharedList(concatenatedData.get());
if (!(data.get(0).isList())) {
throw new IllegalArgumentException("Invalid concatenated storage for AVM.");
}
SharedRLPList pair = (SharedRLPList) data.get(0);
if (pair.size() != 2) {
throw new IllegalArgumentException("Invalid concatenated storage for AVM.");
}
storageRootHash = pair.get(0).getRLPData();
details.objectGraphHash = pair.get(1).getRLPData();
} else {
// As a result the concatenated storage hash cannot be missing from the database.
throw new IllegalArgumentException("Invalid concatenated storage for AVM.");
}
// load/deserialize storage trie
if (input.isExternalStorage) {
// ensure transition from old encoding
details.storageTrie = new SecureTrie(details.externalStorageSource, storageRootHash);
} else {
details.storageTrie = new SecureTrie(null);
details.storageTrie.deserialize((SharedRLPList) storage);
// switch from in-memory to external storage
details.storageTrie.getCache().setDB(details.externalStorageSource);
details.storageTrie.sync();
}
if (Arrays.equals(storageRootHash, ConstantUtil.EMPTY_TRIE_HASH)) {
details.storageTrie = new SecureTrie(details.storageTrie.getCache(), "".getBytes());
}
return details;
}
use of org.aion.zero.impl.trie.SecureTrie in project aion by aionnetwork.
the class FvmContractDetails method decodeAtRoot.
/**
* Decodes an FvmContractDetails object from the RLP encoding and returns a snapshot to the
* specific point in the blockchain history given by the consensus root hash.
*
* @param input the stored encoding representing the contract details
* @param storageSource the data source for the contract storage data
* @param consensusRoot the consensus root linking to specific external storage and object graph
* data at the point of interest in the blockchain history
* @return a snapshot of the contract details with the information it contained at the specified
* point in the blockchain history
*/
public static FvmContractDetails decodeAtRoot(RLPContractDetails input, ByteArrayKeyValueStore storageSource, byte[] consensusRoot) {
Objects.requireNonNull(input, "The contract data for the snapshot cannot be null.");
Objects.requireNonNull(consensusRoot, "The consensus root for the snapshot cannot be null.");
// additional null check are performed by the constructor
FvmContractDetails details = new FvmContractDetails(input.address, storageSource);
RLPElement code = input.code;
if (code instanceof SharedRLPList) {
for (RLPElement e : ((SharedRLPList) code)) {
if (e.isList()) {
details.setCode(SharedRLPList.getRLPDataCopy((SharedRLPList) e));
} else {
details.setCode(e.getRLPData());
}
}
} else if (code instanceof RLPList) {
for (RLPElement e : ((RLPList) code)) {
details.setCode(e.getRLPData());
}
} else {
details.setCode(code.getRLPData());
}
// NOTE: under normal circumstances the VM type is set by the details data store
// Do not forget to set the vmType value externally during tests!!!
RLPElement storage = input.storageTrie;
// load/deserialize storage trie
if (input.isExternalStorage) {
// ensure transition from old encoding
details.storageTrie = new SecureTrie(details.externalStorageSource, consensusRoot);
} else {
details.storageTrie = new SecureTrie(null);
details.storageTrie.deserialize((SharedRLPList) storage);
// switch from in-memory to external storage
details.storageTrie.getCache().setDB(details.externalStorageSource);
details.storageTrie.sync();
}
if (Arrays.equals(consensusRoot, ConstantUtil.EMPTY_TRIE_HASH)) {
details.storageTrie = new SecureTrie(details.storageTrie.getCache(), "".getBytes());
}
return details;
}
use of org.aion.zero.impl.trie.SecureTrie in project aion by aionnetwork.
the class AionRepositoryImpl method getReferencedStorageNodes.
@VisibleForTesting
public List<byte[]> getReferencedStorageNodes(byte[] value, int limit, AionAddress contract) {
if (limit <= 0) {
return Collections.emptyList();
} else {
byte[] subKey = h256(("details-storage/" + contract.toString()).getBytes());
ByteArrayKeyValueStore db = new XorDataSource(selectDatabase(DatabaseType.STORAGE), subKey, false);
Trie trie = new SecureTrie(db);
Map<ByteArrayWrapper, byte[]> refs = trie.getReferencedTrieNodes(value, limit);
List<byte[]> converted = new ArrayList<>();
for (ByteArrayWrapper key : refs.keySet()) {
converted.add(ByteUtil.xorAlignRight(key.toBytes(), subKey));
}
return converted;
}
}
Aggregations