Skip to content

Commit

Permalink
Updated tx info serialization to read data into a map:
Browse files Browse the repository at this point in the history
 - the transaction information is added to the map using as key the block hash
 where the transaction was included in the chain;
 - the actual transaction info data storage remains unchanged;
 - retrieving the transaction information for a specific block is simplified
 by the ability to get it based on the block hash instead of looping through
 the full list of infos stored for all known chains.
  • Loading branch information
AlexandraRoatis committed Oct 21, 2019
1 parent 47654e6 commit 825c7a8
Show file tree
Hide file tree
Showing 5 changed files with 47 additions and 56 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -513,7 +513,7 @@ public List<Block> getBlocksByRange(long first, long last) {
public AionTxInfo getTransactionInfo(byte[] hash) {

// Try to get info if the hash is from an invokable transaction
List<AionTxInfo> infos = getTransactionInfoByAlias(hash);
Map<ByteArrayWrapper, AionTxInfo> infos = getTransactionInfoByAlias(hash);

// If we didn't find the alias for an invokable
if (infos == null || infos.isEmpty()) {
Expand All @@ -525,21 +525,13 @@ public AionTxInfo getTransactionInfo(byte[] hash) {
}

AionTxInfo txInfo = null;
if (infos.size() == 1) {
txInfo = infos.get(0);
} else {
// pick up the receipt from the block on the main chain
for (AionTxInfo info : infos) {
Block block = getBlockStore().getBlockByHash(info.getBlockHash());
if (block == null) continue;

Block mainBlock = getBlockStore().getChainBlockByNumber(block.getNumber());
if (mainBlock == null) continue;

if (Arrays.equals(info.getBlockHash(), mainBlock.getHash())) {
txInfo = info;
break;
}
// pick up the receipt from the block on the main chain
for (ByteArrayWrapper blockHash : infos.keySet()) {
if (!isMainChain(blockHash.toBytes())) {
continue;
} else {
txInfo = infos.get(blockHash);
break;
}
}
if (txInfo == null) {
Expand All @@ -561,16 +553,16 @@ public AionTxInfo getTransactionInfoLite(byte[] txHash, byte[] blockHash) {
return transactionStore.getTxInfo(txHash, blockHash);
}

private List<AionTxInfo> getTransactionInfoByAlias(byte[] innerHash) {
private Map<ByteArrayWrapper, AionTxInfo> getTransactionInfoByAlias(byte[] innerHash) {
Set<ByteArrayWrapper> metaTxHashes = transactionStore.getAliases(innerHash);

if (metaTxHashes == null) return null; // No aliases found

List<AionTxInfo> infoList = new ArrayList<>();
Map<ByteArrayWrapper, AionTxInfo> infoList = new HashMap<>();
for (ByteArrayWrapper metaTxHash : metaTxHashes) {
List<AionTxInfo> metaTxInfos = transactionStore.getTxInfo(metaTxHash.toBytes());
Map<ByteArrayWrapper, AionTxInfo> metaTxInfos = transactionStore.getTxInfo(metaTxHash.toBytes());
if (metaTxInfos != null) {
infoList.addAll(metaTxInfos);
infoList.putAll(metaTxInfos);
}
}
return infoList; // Had metaTx hash, but was not found in mainchain
Expand Down
Original file line number Diff line number Diff line change
@@ -1,37 +1,41 @@
package org.aion.zero.impl.db;

import java.util.ArrayList;
import java.util.List;
import java.util.HashMap;
import java.util.Map;
import org.aion.db.store.Serializer;
import org.aion.log.AionLoggerFactory;
import org.aion.log.LogEnum;
import org.aion.rlp.RLP;
import org.aion.rlp.RLPList;
import org.aion.util.types.ByteArrayWrapper;
import org.aion.zero.impl.types.AionTxInfo;
import org.slf4j.Logger;

public class AionTransactionStoreSerializer {
private static final Logger LOG = AionLoggerFactory.getLogger(LogEnum.TX.toString());

public static final Serializer<List<AionTxInfo>> serializer =
public static final Serializer<Map<ByteArrayWrapper, AionTxInfo>> serializer =
new Serializer<>() {
@Override
public byte[] serialize(List<AionTxInfo> object) {
public byte[] serialize(Map<ByteArrayWrapper, AionTxInfo> object) {
byte[][] txsRlp = new byte[object.size()][];
for (int i = 0; i < txsRlp.length; i++) {
txsRlp[i] = object.get(i).getEncoded();
int i = 0;
for (AionTxInfo info : object.values()) {
txsRlp[i] = info.getEncoded();
i++;
}
return RLP.encodeList(txsRlp);
}

@Override
public List<AionTxInfo> deserialize(byte[] stream) {
public Map<ByteArrayWrapper, AionTxInfo> deserialize(byte[] stream) {
try {
RLPList params = RLP.decode2(stream);
RLPList infoList = (RLPList) params.get(0);
List<AionTxInfo> ret = new ArrayList<>();
Map<ByteArrayWrapper, AionTxInfo> ret = new HashMap<>();
for (int i = 0; i < infoList.size(); i++) {
ret.add(AionTxInfo.newInstanceFromEncoding(infoList.get(i).getRLPData()));
AionTxInfo info = AionTxInfo.newInstanceFromEncoding(infoList.get(i).getRLPData());
ret.put(info.blockHash, info);
}
return ret;
} catch (Exception e) {
Expand Down
11 changes: 6 additions & 5 deletions modAionImpl/src/org/aion/zero/impl/db/DBUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import org.aion.mcf.blockchain.Block;
import org.aion.zero.impl.config.CfgDb;
import org.aion.base.AccountState;
import org.aion.util.types.ByteArrayWrapper;
import org.aion.zero.impl.core.ImportResult;
import org.aion.mcf.db.Repository;
import org.aion.mcf.db.RepositoryCache;
Expand Down Expand Up @@ -702,16 +703,16 @@ public static Status queryTransaction(byte[] txHash) {
AionBlockchainImpl blockchain = new AionBlockchainImpl(cfg, false);

try {
List<AionTxInfo> txInfoList = blockchain.getTransactionStore().getTxInfo(txHash);
Map<ByteArrayWrapper, AionTxInfo> txInfoList = blockchain.getTransactionStore().getTxInfo(txHash);

if (txInfoList == null || txInfoList.isEmpty()) {
System.out.println("Can not find the transaction with given hash.");
return Status.FAILURE;
}

for (AionTxInfo info : txInfoList) {
for (Map.Entry<ByteArrayWrapper, AionTxInfo> entry : txInfoList.entrySet()) {

Block block = blockchain.getBlockStore().getBlockByHash(info.getBlockHash());
Block block = blockchain.getBlockStore().getBlockByHash(entry.getKey().toBytes());
if (block == null) {
System.out.println(
"Can not find the block data with given block hash of the transaction info.");
Expand All @@ -720,7 +721,7 @@ public static Status queryTransaction(byte[] txHash) {
return Status.FAILURE;
}

AionTransaction tx = block.getTransactionsList().get(info.getIndex());
AionTransaction tx = block.getTransactionsList().get(entry.getValue().getIndex());

if (tx == null) {
System.out.println("Can not find the transaction data with given hash.");
Expand All @@ -730,7 +731,7 @@ public static Status queryTransaction(byte[] txHash) {
}

System.out.println(tx.toString());
System.out.println(info.toString());
System.out.println(entry.getValue());
System.out.println();
}

Expand Down
36 changes: 15 additions & 21 deletions modAionImpl/src/org/aion/zero/impl/db/TransactionStore.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,9 @@

import java.io.Closeable;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
Expand All @@ -22,13 +21,12 @@

public class TransactionStore implements Closeable {
private final LRUMap<ByteArrayWrapper, Object> lastSavedTxHash = new LRUMap<>(5000);
private final ObjectStore<List<AionTxInfo>> txInfoSource;
private final ObjectStore<Map<ByteArrayWrapper, AionTxInfo>> txInfoSource;
private final ObjectStore<Set<ByteArrayWrapper>> aliasSource;

private final ReadWriteLock lock = new ReentrantReadWriteLock();

public TransactionStore(
ByteArrayKeyValueDatabase txInfoSrc, Serializer<List<AionTxInfo>> serializer) {
public TransactionStore(ByteArrayKeyValueDatabase txInfoSrc, Serializer<Map<ByteArrayWrapper, AionTxInfo>> serializer) {
txInfoSource = Stores.newObjectStore(txInfoSrc, serializer);
aliasSource = Stores.newObjectStore(txInfoSrc, aliasSerializer);
}
Expand All @@ -40,22 +38,21 @@ public boolean putTxInfoToBatch(AionTxInfo tx) {
try {
byte[] txHash = tx.getReceipt().getTransaction().getTransactionHash();

List<AionTxInfo> existingInfos = null;
Map<ByteArrayWrapper, AionTxInfo> existingInfos = null;
if (lastSavedTxHash.put(ByteArrayWrapper.wrap(txHash), dummy) != null
|| !lastSavedTxHash.isFull()) {
existingInfos = txInfoSource.get(txHash);
}

if (existingInfos == null) {
existingInfos = new ArrayList<>();
existingInfos = new HashMap<>();
} else {
for (AionTxInfo info : existingInfos) {
if (Arrays.equals(info.getBlockHash(), tx.getBlockHash())) {
return false;
}
// TODO: switch to an overwrite policy
if (existingInfos.containsKey(tx.blockHash)) {
return false;
}
}
existingInfos.add(tx);
existingInfos.put(tx.blockHash, tx);
txInfoSource.putToBatch(txHash, existingInfos);

return true;
Expand Down Expand Up @@ -94,22 +91,19 @@ public void flushBatch() {
}

public AionTxInfo getTxInfo(byte[] txHash, byte[] blockHash) {
// ensuring non-null input since this can be called with input from the API
if (txHash == null || blockHash == null) return null;

lock.readLock().lock();

try {
List<AionTxInfo> existingInfos = txInfoSource.get(txHash);
for (AionTxInfo info : existingInfos) {
if (Arrays.equals(info.getBlockHash(), blockHash)) {
return info;
}
}
return null;
return txInfoSource.get(txHash).get(ByteArrayWrapper.wrap(blockHash));
} finally {
lock.readLock().unlock();
}
}

public List<AionTxInfo> getTxInfo(byte[] key) {
public Map<ByteArrayWrapper, AionTxInfo> getTxInfo(byte[] key) {
lock.readLock().lock();
try {
return txInfoSource.get(key);
Expand Down
2 changes: 1 addition & 1 deletion modAionImpl/src/org/aion/zero/impl/types/AionTxInfo.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ public class AionTxInfo {

// note that the receipt is modified to set the transaction
private final AionTxReceipt receipt;
private final ByteArrayWrapper blockHash;
public final ByteArrayWrapper blockHash;
private final int index;
private final List<InternalTransaction> internalTransactions;
private final boolean createdWithInternalTransactions;
Expand Down

0 comments on commit 825c7a8

Please sign in to comment.