package database; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Observable; import java.util.Observer; import java.util.TreeMap; import ntp.NTP; import org.mapdb.BTreeKeySerializer; import org.mapdb.DB; import com.google.common.primitives.UnsignedBytes; import qora.transaction.Transaction; import qora.transaction.TransactionFactory; import utils.ObserverMessage; import utils.TransactionsList; public class TransactionDatabase extends Observable implements Observer { private TransactionDatabase parent; private DBSet databaseSet; private Map<byte[], byte[]> transactionMap; public TransactionDatabase(DBSet databaseSet, DB database) { this.databaseSet = databaseSet; //OPEN MAP this.transactionMap = database.createTreeMap("transactions") .keySerializer(BTreeKeySerializer.BASIC) .comparator(UnsignedBytes.lexicographicalComparator()) .makeOrGet(); } public TransactionDatabase(TransactionDatabase parent) { this.parent = parent; //OPEN MAP this.transactionMap = new TreeMap<byte[], byte[]>(UnsignedBytes.lexicographicalComparator()); } public List<Transaction> getTransactions() { try { //GET ALL TRANSACTIONS IN MAP List<byte[]> keyList = this.getKeys(); if(this.parent != null) { keyList.addAll(this.parent.getKeys()); //TODO REMOVE DUPLICATES } //RETURN return new TransactionsList(keyList); } catch(Exception e) { e.printStackTrace(); return new ArrayList<Transaction>(); } } private List<byte[]> getKeys() { //GET ALL KEYS List<byte[]> keyList = new ArrayList<byte[]>(); for(byte[] key: this.transactionMap.keySet()) { keyList.add(key); } return keyList; } public Transaction getTransaction(byte[] signature) { try { if(this.transactionMap.containsKey(signature)) { return TransactionFactory.getInstance().parse(this.transactionMap.get(signature)); } else { if(this.parent != null) { return this.parent.getTransaction(signature); } } return null; } catch(Exception e) { //NO BLOCK FOUND return null; } } public void addTransaction(Transaction transaction) { try { this.transactionMap.put(transaction.getSignature(), transaction.toBytes()); //COMMIT if(this.databaseSet != null) { this.databaseSet.commit(); } } catch(Exception e) { e.printStackTrace(); } } public void remove(Transaction transaction) { //REMOVE TRANSACTION FROM 0 CONFIRMS this.transactionMap.remove(transaction.getSignature()); //COMMIT if(this.databaseSet != null) { this.databaseSet.commit(); } } public boolean contains(Transaction transaction) { if(this.transactionMap.containsKey(transaction.getSignature())) { return true; } else { if(this.parent != null) { return this.parent.contains(transaction); } } return false; } @Override public void update(Observable o, Object arg) { ObserverMessage message = (ObserverMessage) arg; //ON NEW BLOCK if(message.getType() == ObserverMessage.ADD_BLOCK_TYPE) { //CLEAN UP for(Transaction transaction: this.getTransactions()) { //CHECK IF DEADLINE PASSED if(transaction.getDeadline() < NTP.getTime()) { this.remove(transaction); //NOTIFY this.setChanged(); this.notifyObservers(new ObserverMessage(ObserverMessage.REMOVE_TRANSACTION_TYPE, transaction)); } } } } }