package qora.account; import java.math.BigDecimal; import java.util.Arrays; import controller.Controller; import qora.BlockGenerator; import qora.block.Block; import qora.transaction.Transaction; import database.DBSet; public class Account { public static final int ADDRESS_LENGTH = 25; protected String address; private byte[] lastBlockSignature; private BigDecimal generatingBalance; protected Account() { this.generatingBalance = BigDecimal.ZERO.setScale(8); } public Account(String address) { this.address = address; } public String getAddress() { return address; } //BALANCE public BigDecimal getUnconfirmedBalance() { return this.getUnconfirmedBalance(DBSet.getInstance()); } public BigDecimal getUnconfirmedBalance(DBSet db) { return Controller.getInstance().getUnconfirmedBalance(this.getAddress()); } public BigDecimal getConfirmedBalance() { return this.getConfirmedBalance(DBSet.getInstance()); } public BigDecimal getConfirmedBalance(DBSet db) { return db.getBalanceMap().get(getAddress()); } public BigDecimal getConfirmedBalance(long key) { return this.getConfirmedBalance(key, DBSet.getInstance()); } public BigDecimal getConfirmedBalance(long key, DBSet db) { return db.getBalanceMap().get(getAddress(), key); } public void setConfirmedBalance(BigDecimal amount) { this.setConfirmedBalance(amount, DBSet.getInstance()); } public void setConfirmedBalance(BigDecimal amount, DBSet db) { //UPDATE BALANCE IN DB db.getBalanceMap().set(getAddress(), amount); } public void setConfirmedBalance(long key, BigDecimal amount) { this.setConfirmedBalance(key, amount, DBSet.getInstance()); } public void setConfirmedBalance(long key, BigDecimal amount, DBSet db) { //UPDATE BALANCE IN DB db.getBalanceMap().set(getAddress(), key, amount); } public BigDecimal getBalance(int confirmations) { return this.getBalance(confirmations, DBSet.getInstance()); } public BigDecimal getBalance(int confirmations, DBSet db) { //CHECK IF UNCONFIRMED BALANCE if(confirmations <= 0) { return this.getUnconfirmedBalance(db); } //IF 1 CONFIRMATION if(confirmations == 1) { return this.getConfirmedBalance(db); } //GO TO PARENT BLOCK 10 BigDecimal balance = this.getConfirmedBalance(db); Block block = db.getBlockMap().getLastBlock(); for(int i=1; i<confirmations && block != null && block instanceof Block; i++) { for(Transaction transaction: block.getTransactions()) { if(transaction.isInvolved(this)) { balance = balance.subtract(transaction.getAmount(this)); } } block = block.getParent(db); } //RETURN return balance; } private void updateGeneratingBalance(DBSet db) { //CHECK IF WE NEED TO RECALCULATE if(this.lastBlockSignature == null) { this.lastBlockSignature = db.getBlockMap().getLastBlockSignature(); calculateGeneratingBalance(db); } else { //CHECK IF WE NEED TO RECALCULATE if(!Arrays.equals(this.lastBlockSignature, db.getBlockMap().getLastBlockSignature())) { this.lastBlockSignature = db.getBlockMap().getLastBlockSignature(); calculateGeneratingBalance(db); } } } public void calculateGeneratingBalance(DBSet db) { //CONFIRMED BALANCE + ALL NEGATIVE AMOUNTS IN LAST 9 BLOCKS BigDecimal balance = this.getConfirmedBalance(db); Block block = db.getBlockMap().getLastBlock(); for(int i=1; i<BlockGenerator.RETARGET && block != null && block.getHeight(db) > 1; i++) { for(Transaction transaction: block.getTransactions()) { if(transaction.isInvolved(this)) { if(transaction.getAmount(this).compareTo(BigDecimal.ZERO) == 1) { balance = balance.subtract(transaction.getAmount(this)); } } } block = block.getParent(db); } //DO NOT GO BELOW 0 if(balance.compareTo(BigDecimal.ZERO) == -1) { balance = BigDecimal.ZERO.setScale(8); } this.generatingBalance = balance; } public BigDecimal getGeneratingBalance() { return this.getGeneratingBalance(DBSet.getInstance()); } public BigDecimal getGeneratingBalance(DBSet db) { //UPDATE updateGeneratingBalance(db); //RETURN return this.generatingBalance; } //REFERENCE public byte[] getLastReference() { return this.getLastReference(DBSet.getInstance()); } public byte[] getLastReference(DBSet db) { return db.getReferenceMap().get(this); } public void setLastReference(byte[] reference) { this.setLastReference(reference, DBSet.getInstance()); } public void setLastReference(byte[] reference, DBSet db) { db.getReferenceMap().set(this, reference); } public void removeReference() { this.removeReference(DBSet.getInstance()); } public void removeReference(DBSet db) { db.getReferenceMap().delete(this); } //TOSTRING @Override public String toString() { return this.getBalance(0).toPlainString() + " - " + this.getAddress(); } public String toString(long key) { return this.getConfirmedBalance(key).toPlainString() + " - " + this.getAddress(); } //EQUALS @Override public boolean equals(Object b) { if(b instanceof Account) { return this.getAddress().equals(((Account) b).getAddress()); } return false; } }